2013-09-27 2 views
16

Использование Google Guava (Google Commons), есть ли способ объединить два одинаковых размера списка в один список, с новым списком, содержащим составные объекты из двух входных списков?Google Guava «zip» два списка

Пример:

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)] 
+0

Зачем вам нужна специализированная функция для этого, почему бы не просто написать простой? – arshajii

+5

Все, что может предложить Гувава, было бы более сложным в использовании, чем простой цикл 'for', который является коротким и простым в любом случае. –

+0

Есть ли что-то, что вы нам не говорите? В примере, который вы цитируете, смешно ожидать, что внешняя библиотека ничего не знает о вашем классе «Личность» ... объем рефлексии, необходимый для выполнения того, что вы хотите, замедлит его гораздо больше, чем достаточно очевидный ответ ниже. – dcsohl

ответ

16

Похоже, что этого нет в Гуаве, но это желаемая функция. См. this github issue, в частности Iterators.zip().

10

Просто вид это метод гуавы:

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

Этот ответ промахивается. Конечно, я могу написать цикл for. Я ищу общий способ применить шаблон «zip» к двум коллекциям. Если завтра мне нужно объединить 'X' и 'Y' в список 'Z', мне придется скопировать вышеуказанный код и изменить его. –

+7

@SteveKuo: Какой API может предложить Guava, что приведет к более короткому решению, чем это? Даже если Guava добавил интерфейс «BiFunction» или что-то еще, и метод «zipWith», получившийся анонимный класс будет длиннее этого простого цикла 'for'. –

+2

См. «Функциональные идиомы в Гуаве, объясненные» для концепции использования преобразования https://code.google.com/p/guava-libraries/wiki/FunctionalExplained –

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

Это действительно не намного лучше, чем с явной итерации, и вы, вероятно, хотите некоторый уровень проверки границ, чтобы гарантировать, что два входа действительно одного и того же размера.

0

Вы можете обратиться к underscore-java library.

Underscore-java - это порт Underscore.js для Java, а способ zip может достигать цели.

Ниже приведен пример кода & выход:

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

=> [[МОС, 30], [Larry, 40], [фигурные, 50]]

+0

Thats javascript not java. –

+0

> Underscore-java - это порт Underscore.js для Java –

15

По состоянию Гуава 21, это возможно через Streams.zip():

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

Это должно стать более высоким! – cubuspl42

Смежные вопросы