Java 谷歌番石榴“压缩”两个列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19040802/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:36:16  来源:igfitidea点击:

Google Guava "zip" two lists

javaguava

提问by Steve Kuo

Using Google Guava (Google Commons), is there a way to merge two equally sized lists into one list, with the new list containing composite objects of the two input lists?

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

Example:

例子:

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 + ")";
    }
}

and

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);

Would output:

会输出:

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

采纳答案by shmosel

As of Guava 21, this is possible via Streams.zip():

从番石榴 21 开始,这可以通过Streams.zip()

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

回答by stepanian

Just pretend this is a Guava method:

假设这是一个番石榴方法:

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

回答by Steve Kuo

Looks like this is not currently in Guava, but is a desired feature. See this github issue, in particular Iterators.zip().

看起来这目前不在 Guava 中,但它是一个需要的功能。请参阅此 github 问题,特别是Iterators.zip()

回答by Zhe

Here's a version with no explicit iteration, but it's getting pretty ugly.

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

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));
      }
    }));

It's really not much better than having explicit iteration, and you probably want some level of bounds checking to ensure that the two inputs are indeed of the same size.

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

回答by sheldon shen

You can refer to underscore-java library.

您可以参考underscore-java 库

Underscore-javais a port of Underscore.jsfor Java, and the zipmethod can achieve the goal.

Underscore-javaUnderscore.jsJava的一个端口,该zip方法可以达到目的。

Following is a sample code & output :

以下是示例代码和输出:

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

=> [[moe, 30], [larry, 40], [curly, 50]]

=> [[moe, 30], [larry, 40], [curly, 50]]

回答by Benny Bottema

Here's a generic way to zip lists with vanilla Java. Lacking tuples, I opted to use a list of map entries (If you don't like to use map entries, introduce an additional class ZipEntryor something).

这是使用 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;
}

To support arrays as well:

也支持数组:

@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[] {});
}

To make it more robust add precondition checks on list sizes etc, or introduce left join/ right joinsemantics similar to SQL queries.

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