如何最优雅地迭代并行集合?

tek*_*ara 49 java collections

假设我有2个并行集合,例如:a中的人名List<String>列表以及a List<Int>中相同顺序的年龄列表(以便每个集合中的任何给定索引指向同一个人).

我想同时遍历这两个集合,并获取每个人的姓名和年龄,并用它做一些事情.使用数组,这很容易完成:

for (int i = 0; i < names.length; i++) {
   do something with names[i] ....
   do something with ages[i].....
}
Run Code Online (Sandbox Code Playgroud)

使用集合执行此操作的最优雅方式(在可读性和速度方面)是什么?

Mar*_*wis 65

it1 = coll1.iterator();
it2 = coll2.iterator();
while(it1.hasNext() && it2.hasNext()) {
   value1 = it1.next();
   value2 = it2.next();
   do something with it1 and it2;
}
Run Code Online (Sandbox Code Playgroud)

当较短的集合耗尽时,此版本终止; 或者,您可以继续,直到较长的一个用尽,设置值1.value2为null.

  • 这实际上是官方答案:"当你需要时,使用Iterator而不是for-each构造:...并行迭代多个集合." [The Java™Tutorials:The Collection Interface](http://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html) (5认同)
  • 要处理第一个耗尽的列表,您可以使用 `value1 = it1.hasNext() ?it1.next() : null;`(与`it2`同上)在获取下一个元素之前进行检查。或者,您可以将 try-catch 与“NoSuchElementException”一起使用,它有点长。 (3认同)

jee*_*ef3 32

我会创建一个封装两者的新对象.把它扔进数组并迭代它.

List<Person>
Run Code Online (Sandbox Code Playgroud)

哪里

public class Person {
    public string name;
    public int age;
}
Run Code Online (Sandbox Code Playgroud)

  • 当给出单独的名称和年龄输入列表时,它并没有完全回答如何创建这样的List的问题.因此,在这种情况下仍然需要迭代两者的优雅方式. (17认同)
  • 当你能够重构你的代码以使用一个列表时,这是一个很好的建议,但如果你真的从两个单独的列表开始(例如,如果它们来自不同的列表),这个答案将无法描述*如何构建这样的列表数据源). (3认同)
  • +1 - 非常合理的建议,因为它是最可扩展的 (2认同)
  • 这是显而易见的解决方案 - 正确定义对象和域:年龄和名称是人的属性.将它们映射并使用它们. (2认同)
  • 这是惯用的Java答案:为其定义类型。请参阅[Java中C ++ Pair &lt;L,R&gt;的等效项是什么?](http://stackoverflow.com/questions/156275/what-is-the-equivalent-of-the-c-pairl-r- Java中),以防止在Java中不鼓励使用匿名对。 (2认同)

cle*_*tus 10

您可以为它创建一个接口:

public interface ZipIterator<T,U> {
  boolean each(T t, U u);
}

public class ZipUtils {
  public static <T,U> boolean zip(Collection<T> ct, Collection<U> cu, ZipIterator<T,U> each) {
    Iterator<T> it = ct.iterator();
    Iterator<U> iu = cu.iterator();
    while (it.hasNext() && iu.hasNext()) {
      if (!each.each(it.next(), iu.next()) {
        return false;
      }
    }
    return !it.hasNext() && !iu.hasNext();
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你有:

Collection<String> c1 = ...
Collection<Long> c2 = ...
zip(c1, c2, new ZipIterator<String, Long>() {
  public boolean each(String s, Long l) {
    ...
  }
});
Run Code Online (Sandbox Code Playgroud)

  • 使用Java 8的lambdas,你甚至可以这样使用它:`zip(c1,c2,(s,l) - > ...)`.(另外,您的ZipIterator与BiConsumer基本相同.) (3认同)

And*_*lla 8

for (int i = 0; i < names.length; ++i) {
  name = names.get(i);
  age = ages.get(i);
  // do your stuff
}
Run Code Online (Sandbox Code Playgroud)

这并不重要.你的代码不会得到优雅的分数.只要这样做就可以了.请不要膨胀.

  • 在此预先警告并非所有列表都具有高效的get(int)实现.双迭代器不太可能效率低下. (9认同)