Google Guava“zip”两个列表

使用Google Guava(Google Commons),有没有办法将两个大小相同的列表合并为一个列表,新列表包含两个输入列表的复合对象?

例:

public class Person { public final String name; public final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String toString() { return "(" + name + ", " + age + ")"; } } 

 List names = Lists.newArrayList("Alice", "Bob", "Charles"); List ages = Lists.newArrayList(42, 27, 31); List persons = transform with a function that converts (String, Integer) to Person System.out.println(persons); 

输出:

 [(Alice, 42), (Bob, 27), (Charles, 31)] 

从Guava 21开始,这可以通过Streams.zip()

 List persons = Streams.zip(names.stream(), ages.stream(), Person::new) .collect(Collectors.toList()); 

看起来这个目前不在Guava中,但是是一个理想的function。 请参阅此github问题 ,尤其是Iterators.zip()

只是假装这是一种番石榴方法:

 for (int i = 0; i < names.size(); i++) { persons.add(new Person(names.get(i), ages.get(i))); } 

你可以参考underscore-java库 。

Underscore-javaUnderscore.js for Java的一个端口, zip方法可以实现目标。

以下是示例代码和输出:

 $.zip(Arrays.asList("moe", "larry", "curly"), Arrays.asList("30", "40", "50")); 

= [[moe,30],[larry,40],[curl,50]]

这是一个没有明确迭代的版本,但它变得非常难看。

 List persons = ImmutableList.copyOf(Iterables.transform( ContiguousSet.create(Range.closedOpen(0, names.size()), DiscreteDomain.integers()), new Function() { @Override public Person(Integer index) { return new Person(names.get(index), ages.get(index)); } })); 

它实际上没有比显式迭代好多少,并且您可能需要某种程度的边界检查以确保两个输入确实具有相同的大小。

这是使用vanilla Java压缩列表的通用方法。 缺少元组,我选择使用地图条目列表(如果你不喜欢使用地图条目,引入一个额外的类ZipEntry或其他东西)。

 public static  List> zip(List zipLeft, List zipRight) { List> zipped = new ArrayList<>(); for (int i = 0; i < zipLeft.size(); i++) { zipped.add(new AbstractMap.SimpleEntry<>(zipLeft.get(i), zipRight.get(i))); } return zipped; } 

也支持数组:

 @SuppressWarnings("unchecked") public static  Map.Entry[] zip(T1[] zipLeft, T2[] zipRight) { return zip(asList(zipLeft), asList(zipRight)).toArray(new Map.Entry[] {}); } 

为了使其更健壮,在列表大小等上添加前置条件检查,或引入类似于SQL查询的左连接 / 右连接语义。