Google Guava(Google Commons)を使用して、2つの同じサイズのリストを1つのリストにマージし、新しいリストに2つの入力リストの複合オブジェクトを含める方法はありますか?
例:
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)]
Guava 21の時点で、これは Streams.Zip()
:を介して可能です。
List<Person> persons = Streams.Zip(names.stream(), ages.stream(), Person::new)
.collect(Collectors.toList());
これは現在Guavaにはないようですが、望ましい機能です。 このgithubの問題 、特にIterators.Zip()
を参照してください。
これがGuavaメソッドであると偽ってください。
for (int i = 0; i < names.size(); i++) {
persons.add(new Person(names.get(i), ages.get(i)));
}
アンダースコア-Javaライブラリ を参照できます。
Underscore-Java
はJava用のUnderscore.js
のポートであり、Zip
メソッドは目標を達成できます。
以下はサンプルコードと出力です:
$.Zip(Arrays.asList("moe", "larry", "curly"), Arrays.asList("30", "40", "50"));
=> [[moe、30]、[larry、40]、[curly、50]]
VanillaJavaを使用してリストをZipする一般的な方法は次のとおりです。タプルがないため、マップエントリのリストを使用することにしました(マップエントリを使用したくない場合は、追加のクラス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クエリと同様のセマンティクスを導入します。
これは明示的な反復のないバージョンですが、かなり醜いものになっています。
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));
}
}));
明示的な反復を行うよりも実際にはそれほど良くはありません。おそらく、2つの入力が実際に同じサイズであることを確認するために、ある程度の境界チェックが必要です。