24

使用 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<String> names = Lists.newArrayList("Alice", "Bob", "Charles");
List<Integer> ages = Lists.newArrayList(42, 27, 31);

List<Person> persons =
    transform with a function that converts (String, Integer) to Person
System.out.println(persons);

会输出:

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

6 回答 6

31

从 Guava 21 开始,这可以通过以下方式实现Streams.zip()

List<Person> persons = Streams.zip(names.stream(), ages.stream(), Person::new)
                              .collect(Collectors.toList());
于 2017-06-27T08:49:41.053 回答
16

看起来这目前不在 Guava 中,但它是一个理想的功能。尤其是看到这个 github 问题Iterators.zip()

于 2013-09-27T16:05:16.857 回答
10

假设这是一个 Guava 方法:

for (int i = 0; i < names.size(); i++) {
    persons.add(new Person(names.get(i), ages.get(i)));
}
于 2013-09-27T02:45:05.143 回答
2

可以参考underscore-java 库

Underscore-javaUnderscore.jsfor Java的一个port,zip方法可以达到目的。

以下是示例代码和输出:

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

=> [[萌,30],[拉里,40],[卷曲,50]]

于 2017-06-27T08:40:52.047 回答
1

这是使用 vanilla Java 压缩列表的通用方法。由于缺少元组,我选择使用映射条目列表(如果您不喜欢使用映射条目,请引入额外的类ZipEntry或其他东西)。

public static <T1,T2> List<Map.Entry<T1,T2>> zip(List<T1> zipLeft, List<T2> zipRight) {
    List<Map.Entry<T1,T2>> 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 <T1,T2> Map.Entry<T1,T2>[] zip(T1[] zipLeft, T2[] zipRight) {
    return zip(asList(zipLeft), asList(zipRight)).toArray(new Map.Entry[] {});
}

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

于 2018-08-26T12:21:44.497 回答
0

这是一个没有显式迭代的版本,但它变得非常丑陋。

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

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

于 2016-06-09T14:45:37.570 回答