9

在同时处理 2 个元素的同时迭代列表的最佳方法是什么?

例子:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
for(int i = 0; i < strings.size(); i++){
    String first = strings.get(i);
    String second = null;
    if(strings.size() > i + 1){
        second = strings.get(i + 1);
    }
    System.out.println("First [" + first + "] - Second [" + second + "]");
}

结果是:

First [item 1] - Second [item 2]
First [item 2] - Second [item 3]
First [item 3] - Second [item 4]
First [item 4] - Second [null]

我想实现:

First [item 1] - Second [item 2]
First [item 3] - Second [item 4]
4

11 回答 11

16

只需增加i2:

for(int i = 0; i < strings.size() - 2; i += 2) {
    String first = strings.get(i);
    String second = strings.get(i+1);
于 2013-04-16T09:47:30.037 回答
8

我使用 Java8 BiConsumer 创建了以下方法:

public static <T> void tupleIterator(Iterable<T> iterable, BiConsumer<T, T> consumer) {
    Iterator<T> it = iterable.iterator();
    if(!it.hasNext()) return;
    T first = it.next();

    while(it.hasNext()) {
        T next = it.next();
        consumer.accept(first, next);
        first = next;
    }
}

像这样使用它:

List<String> myIterable = Arrays.asList("1", "2", "3");
tupleIterator(myIterable, (obj1, obj2) -> {
    System.out.println(obj1 + " " + obj2);
});

这将输出:

1 2
2 3
于 2015-08-20T19:24:39.353 回答
7

您需要修改并增加i第二个值,修改语句:

second = strings.get(i + 1);

second = strings.get(++i);

这也会增加i,因为这似乎是所需的行为。

所以你的代码是:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
for(int i = 0; i < strings.size(); i++){
    String first = strings.get(i);
    String second = null;
    if(strings.size() > i + 1){
        second = strings.get(++i); //Change here
    }
    System.out.println("First [" + first + "] - Second [" + second + "]");
}
于 2013-04-16T09:45:19.553 回答
4
List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");    
int i = 0;  
for(; i < strings.size() - 1; i+=2){  
    String first = strings.get(i);  
    String second =  strings.get(i + 1);  
    System.out.println("First [" + first + "] - Second [" + second + "]");  
}  
//For odd sized lists
if(i < strings.size()){         
    System.out.println("First [" + strings.get(i) + "]");  
}
于 2013-04-16T09:48:51.697 回答
2

如果在每次迭代中将 i 增加 2 会怎样?应该这样做...否则考虑在实际循环中增加 i

于 2013-04-16T09:47:10.173 回答
2

我们当然应该为一般情况提供解决方案;-)

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
    for (Pair<Integer> p : Pair.over(list)) {
        System.out.printf("%d, %d\n", p.first, p.second);
    }
}

static class Pair<T> {
    T first;

    T second;

    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public static <T> Iterable<Pair<T>> over(Collection<T> collection) {
        return new PairWise<T>(collection);
    }

    private static class PairWise<T> implements Iterable<Pair<T>>, Iterator<Pair<T>> {

        final Iterator<T> iterator;

        PairWise(Collection<T> collection) {
            super();
            this.iterator = collection.iterator();
        }

        @Override
        public Iterator<Pair<T>> iterator() {
            return this;
        }

        @Override
        public boolean hasNext() {
            return iterator.hasNext();
        }

        @Override
        public Pair<T> next() {
            T first = null;
            T second = null;
            if (iterator.hasNext())
                first = iterator.next();
            else
                throw new NoSuchElementException();
            if (iterator.hasNext())
                second = iterator.next();
            return new Pair<T>(first, second);
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

    }
}
于 2013-04-16T10:18:53.007 回答
1

您可以避免使用Iterator进行索引;这适用于任何Iterable,而不仅仅是列表。只需获取一个迭代器并在每次循环迭代中将其递增两次:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
Iterator<String> stringsIterator = strings.iterator();
while (stringsIterator.hasNext()) {
  String first = stringsIterator.next();
  String second = stringsIterator.next();
  System.out.println("First [" + first + "] - Second [" + second + "]");
}

这假设一个偶数长度的列表,NoSuchElementException如果它是奇数长度,则在最后一次传递。您可以通过多种方式处理此问题:

  • 使用try- catch;
  • 有一个保护子句,可以预先检查长度是否相等;
  • 在获取第二个元素之前检查。

检查第二个元素:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3");
Iterator<String> stringsIterator = strings.iterator();
while (stringsIterator.hasNext()) {
  String first = stringsIterator.next();
  String second = stringIterator.hasNext() ? stringIterator.next() : null;
  System.out.println("First [" + first + "] - Second [" + second + "]");
}

迭代器会使一些人感到困惑,因此您还可以使用带有分支的 for-each 循环和用于奇偶校验的辅助触发器变​​量。这更糟糕,因为它使循环的逻辑变得更加复杂,以简化迭代:与其每次通过循环执行一次操作,按顺序且没有分支,而是必须经过两次并在心理上进行分支。请注意,如果它的长度为奇数,则会跳过最后一个元素;isFirst如果也想处理这些情况,可以在事后添加检查。

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
boolean isFirst = true;
String first = null;
String second = null;
for (String string : strings) {
  if (isFirst) {
    first = string;
    isFirst = false;
  } else {
    second = string;
    isFirst = true;
    System.out.println("First [" + first + "] - Second [" + second + "]");
  }
}

最后,请注意,所有这些迭代器和辅助变量都有多余的范围(它们仅用于循环本身,因此它们会污染本地环境):它们可以包装在块中以限制范围,尽管通常会考虑生成的嵌套比超出范围更糟糕:

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
{
  Iterator<String> stringsIterator = strings.iterator();
  while (stringsIterator.hasNext()) {
    String first = stringsIterator.next();
    String second = stringsIterator.next();
    System.out.println("First [" + first + "] - Second [" + second + "]");
  }
}
于 2015-06-03T05:28:32.450 回答
1

现在在 Java 8 中,通过使用https://github.com/wapatesh/fig

你可以写:

seq.forEachSlice(2, (values)->{
    // [1,2]  [3, 4]
});
于 2015-08-03T08:35:10.203 回答
0
for(int i = 0; i < strings.size(); i++){
    String first = strings.get(i++);
    String second = null;
    if(strings.size() > i){
        second = strings.get(i);
    }
    System.out.println("First [" + first + "] - Second [" + second + "]");
}
于 2013-04-16T09:48:08.897 回答
0

为了提高性能,我建议您只计算一个列表的大小,而不是在每个新循环中创建一个新字符串。

List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
int length = strings.size();
String first, second = null;
for(int i = 0; i < length; i += 2){
    ...
}
于 2013-04-16T09:57:03.053 回答
0
List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
for(int i = 0; i < strings.size(); i++){
    if(i½2 = 0){
        String first = strings.get(i);
        System.out.print("First [" + first + "] ");
    }else{
         String second = strings.get(i + 1);
         System.out.println("- Second [" + second + "]");
    }
}
于 2013-04-16T09:50:29.007 回答