如何在Java中并行迭代多个列表?

5
我希望创建一个函数来迭代多个列表。现在我知道这些列表的大小完全相同(它们也可以具有不同的类型),例如:
List<Integer> list1 = getList1();
List<String> list2 = getList2();
List<Long> list3 = getList3();
list1.size() == list2.size(); // returns true
list2.size() == list3.size(); // returns true

我希望你能够调用一个函数,它可以同时获取这些列表中同一位置的3个元素。例如:

int calculate(int elemList1, String elemList2, long elemList3) {...}

// iterator over the lists in parallel {
    int ret = calculate(elemList1, elemList2, elemList3);
// }

我想做类似于guava中讨论过但尚未实现的事情,这里是链接:http://code.google.com/p/guava-libraries/issues/detail?id=677

他们谈到了Iterators.interleave或Iterators.zip,我想做类似的事情,但我还没有能够做到,所以有人可以帮我一下吗?谢谢!

我希望不必获取一个列表的大小并按索引迭代它们,因为将来可能会有不同大小的列表,所以我想只使用一种方法来处理。


你是想使用zip技术同时迭代多个列表,还是在这里尝试进行多线程操作? - Platinum Azure
如果我没记错的话,这个从未被决定,因此也从未实施。我通过创建一个按索引键控的multimap并添加每个集合的项来伪造它(因为我无法保证这些集合类似于ArrayList,因此get(n)不具有确定性)。 - Dave Newton
不,我只是想同时迭代,使用类似于zip的东西,就像我解释的那样。我想做类似于Guava讨论的事情。 - darkuzul
Guava解决方案似乎具有处理大小不同的列表的逻辑,而您并不需要。 - Rob
3个回答

12

复合迭代器可能是一个很酷的想法,例如:

Iterator<Array<?>> compoundIterator = createIterator(List1, List2, List3);

然后,在实现中,你将为每个列表创建迭代器,然后循环遍历项目并将它们放入数组中,那么你对这些内容的使用将类似于:

while (compoundIterator.hasElements()){
    Array[] elements = compountIterator.nextElement();
    calculate(elements[0], elements[1], elements[2]);
}

这种解决方案的好处在于,你可以隐藏所有关于是否有列表用完的细节(当然,你必须决定如果其中一个用完该怎么办,但这也可以包含在内部)。


我喜欢这个解决方案,谢谢!创建一个迭代器实现难吗?我需要做些什么来回报你的答案吗? - darkuzul
只需单击复选框即可奖励。不,编写自己的迭代器很容易,并且是一个很好的练习。 - Rob
当然。如果您有问题,请再次发布,但您只是提供了两种方法的实现,这两种方法将被委托。 :) - Rob
我更喜欢您作为其他答案发布的简单解决方案。在这种情况下,您必须将每个数组元素转换为正确的类型。我看不出此方法的好处。 - Christoph Leiter
这个答案中的语法有点令人困惑。Array是什么?为什么它是Array<?>,然后又是Array[]?你是不是想说Object[] - Paul Bellora
显示剩余2条评论

2
你可以创建一个新线程并在其中迭代列表。生成多个此线程,你就可以并行迭代列表。
如果你想传递任何模板类型的列表,只需将方法参数指定为List,尽管这可能会导致编译器警告。另一种尝试的方法是将列表作为List<T extends Object>传递,并根据类型T进行运行时检查并采取相应措施。
但是,如果你所指的“并行”不是指多线程/并发,而只是希望能够在一个单独的循环中迭代三个列表,则可以使用类似以下代码(警告:此代码仅是粗略示例,未经测试/符合编码规范)。
List list1 = ...
List list2 = ...
List list3 = ...

for(int i=0,j=0,k=0; i<list1.size() && j<list2.size() && k<list3.size(); ++i,++j,++k)
{
   Object elemOfList1 = list1.get(i);
   Object elemOfList2 = list2.get(j);
   Object elemOfList3 = list3.get(k);
   // do something here
}

但是我需要对这些列表的一个切片应用一个函数(我编辑了我的帖子来解释),如果我必须使用线程或者必须制作复杂的逻辑来同步,那么我就无法做到这一点,对吧? - darkuzul
在这种情况下,建议您阅读一下Java 7的新Fork/Join特性,看看它是否能帮助您:http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html - gerrytan
我不明白为什么需要使用线程,我只需要并行迭代列表,在每次迭代中应用函数,有没有避免使用线程的方法? - darkuzul
你如何在没有多个线程的情况下并行执行某些操作?我认为这是不可能的。 - gerrytan
Guava.zip 的想法正是我想要实现的,但似乎没有涉及任何线程。 - darkuzul

1

我认为你并没有真正地说“并行”,因为这些值被用于调用一个方法。如果你想要从每个列表中获取相同的元素,那么在不同的线程上同时跳过不同的列表是没有意义的。

你只需要使用for循环,然后调用list1.get(i),list2.get(i),list3.get(i)。


谢谢你,Rob。我也考虑过这个问题,但我更想采用迭代器方法,而不是通过索引调用列表。我认为Guava讨论的正是我想要做的,但还没有实现。 - darkuzul
就像我说的那样,这让你能够看到是否已经到了结尾。你没有这个问题吗? - Rob
它能够工作,但将来我可能会有不同大小的列表,我也希望能够处理它,谢谢。 - darkuzul
当然。另一个很酷的事情可能是制作自己的迭代器,它是其他迭代器的聚合器,然后返回一个数组。我会将其添加为另一个答案。 - Rob
是的,我认为那正是我所需要的,谢谢你的帮助。 - darkuzul
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接