【问题标题】:How do I iterate over multiple lists in parallel in Java? [duplicate]如何在 Java 中并行迭代多个列表? [复制]
【发布时间】:2013-01-25 00:39:18
【问题描述】:

我想创建一个函数来迭代多个列表。现在我知道这些列表的大小完全相同(它们也可以有不同的类型),例如:

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 技术同时迭代多个列表,还是实际上在这里尝试多线程?
  • IIRC 这从未被决定,因此从未实施。我通过创建一个以索引为键的多映射并添加每个集合的项目来伪造它(因为我不能保证集合类似于 ArrayList,所以 get(n) 不是确定性的)。
  • 不,我只是想同时使用类似 zip 的东西进行迭代,就像我解释的那样,我想做一些类似于他们在 guava 上讨论的事情。
  • Guava 解决方案看起来具有处理您不需要的不同大小列表的逻辑。

标签: java iterator guava


【解决方案1】:

复合迭代器可能是个好主意,例如:

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

然后在实现中,您将为每个列表创建迭代器,然后循环遍历项目并将它们放入数组中,然后您对这些内容的使用将如下所示:

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

这个解决方案的好处是你隐藏了所有关于一个列表是否用完的细节(当然你必须决定如果一个列表用完,你想做什么,但这也可以包含在里面)。

【讨论】:

  • 我喜欢这个解决方案谢谢我会这样做!创建迭代器实现是否需要人力资源?我需要做些什么来奖励你的回答吗?
  • 只需点击复选框即可获得奖励。不,做你自己的迭代器很容易,而且是一个很好的练习。
  • 当然。如果您有问题,请再次发布,但您只是提供您将要委派的两种方法的实现。 :)
  • 我更喜欢您发布的简单解决方案作为您的其他答案。在这种情况下,您必须将每个数组元素转换为正确的类型。我没有看到这种方法的好处。
  • 如果您要从数组提供输入,那么强制转换可能不是一个重要的考虑因素。我是一个铁杆 OO 人,我认为你应该对所有事情都使用对象,但也就是说,我看到了聚合迭代器的潜在价值。坦率地说,您可以通过参数化类型来解决您的反对意见,例如复合聚合器。然后就不会有强制转换(不,你不能做可变数量的类型参数,但是你想要同时处理的事情可能有一个限制)。
【解决方案2】:

我不认为你真的在说并行,因为这些值被用来调用一个方法。如果您想要每个列表中的相同元素,同时跳过不同线程上的不同列表没有好处。

您只需要执行一个 for 循环,然后调用 list1.get(i)、list2.get(i)、list3.get(i)。

【讨论】:

  • 谢谢 Rob,我也想过这个问题,但我想做更多的迭代器方法,而不是通过索引调用列表,我认为番石榴讨论正是我想要的要做但未实施
  • 正如我所说,这使您能够查看自己是否在最后。你没有这个问题吗?
  • 它可以工作,但将来我可以拥有不同大小的列表,我也希望能够处理这个问题。
  • 当然。另一件很酷的事情是可能创建自己的迭代器,它是其他迭代器的聚合器,然后返回一个数组。我将其添加为另一个答案。
  • 是的,我认为这正是我想要的,谢谢你的帮助。
【解决方案3】:

您可以创建一个新线程并在那里迭代您的列表。产生多个这个 therad,你可以并行迭代你的列表。

如果您想传递任何模板类型的 List,您只需将您的方法参数指定为 List,尽管这可能会导致编译器警告。您可以尝试的其他事情是将列表作为 List 传递,并执行 T 类型的运行时检查并相应地执行操作

但是,如果您所说的“并行”不是指多线程/并发 - 而只是希望能够在一个循环中迭代您的 3 个列表,那么这样的事情就可以了(警告代码只是粗略的示例 -未测试/符合编码标准):

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
}

【讨论】:

  • 但是我需要为这些列表的一部分应用一个函数(我编辑了我的帖子来解释),如果我必须使用线程或者我必须制作复杂的逻辑来同步否?
  • 在这种情况下,请阅读新的 Java 7 Fork/Join 功能,看看它是否可以帮助您:docs.oracle.com/javase/tutorial/essential/concurrency/…
  • 我不明白为什么我需要线程,我只需要并行迭代列表以在每次迭代时应用一个函数,有没有办法避免线程?
  • 如何在没有多个线程的情况下并行执行某些操作?我不认为你可以..
  • guava.zip 的想法正是我想做的,但它似乎不涉及任何线程。
猜你喜欢
  • 1970-01-01
  • 2014-03-21
  • 2018-10-04
  • 2022-12-06
  • 2015-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多