我遇到这种情况,似乎Java 8 Streams API会有所帮助,但我不完全确定它是怎么回事。
从两个具有不同元素类型的集合中,我想构建第三个集合,其元素是来自两个集合的所有可能的 Pairs 元素。基本上是:
两种不同的元素类型......
public class A {}
public class B {}
As和Bs的“配对”。
public class Pair {
private A a;
private B b;
public Pair(A a, B b){
this a = a;
this b = b;
}
}
使用旧式java.util.Collection
API制作的“组合”:
public Collection<Pair> combine(Collection<A> as, Collection<B> bs){
Collection<Pair> pairs = new ArrayList();
foreach(A a: as){
foreach(B b: bs){
Pair pair = new Pair(a,b);
pairs.add(pair);
}
}
return pairs;
}
结果对集合中的排序并不重要。因此,可以创建Pair的每个实例并将其并行添加到结果集合中。我怎么能做到这一点?
我自己能想到的最好的方法是使用Streams版本的foreach
:
as.foreach(
a -> {
bs.foreach(
b -> {
Pair pair = new Pair(a,b);
pairs.add(pair);
}
}
);
为简化起见,这个例子变得微不足道。类Pair
是将两个元素处理为第三个元素(即java.util.function.BiFunction
)的示例,将它们添加到Collection
只是可变缩减的一个示例。 / p>
有更优雅的方式吗?或者更可取的是,在效率方面以更有利可图的方式?像
这样的东西BiFunction<A,B,Pair> combinator = Pair::new; //or any other function f(a,b)=c;
Stream<Pair> pairStream =
Streams.unknownElegantMethod(as.stream(), bs.stream(), combinator);
答案 0 :(得分:23)
我希望我没有任何愚蠢的错别字,但基本上你可以做的是:
List<Pair> list = as
.stream()
.flatMap(a -> bs.stream().map (b -> new Pair(a,b)))
.collect (Collectors.toList());
Stream<A>
创建as
。a
实例Stream<B>
bs
的{{1}}
2.2将每个b
映射到一对(a,b)
答案 1 :(得分:4)
如果您愿意使用第三方库,则可以使用Eclipse Collections Sets.cartesianProduct()
。这将要求你的a和b都是套装。 Eclipse Collections内置了Pair
类型,因此您无需创建它。
public class A {}
public class B {}
public List<Pair<A, B>> combine(Set<A> as, Set<B> bs)
{
return Sets.cartesianProduct(as, bs).toList();
}
如果你的a和b不是套装,那么你可以使用CollectionAdapter
flatCollect
和collect
,它们相当于flatMap
和map
Stream
。
public Collection<Pair<A, B>> combine(Collection<A> as, Collection<B> bs)
{
MutableCollection<B> adaptB = CollectionAdapter.adapt(bs);
return CollectionAdapter.adapt(as)
.flatCollect(a -> adaptB.asLazy().collect(b -> Tuples.pair(a, b)));
}
使用Stream
的另一个可能选项是为Collector
定义自己的cartesianProduct
。这比其他Stream
解决方案更复杂,只有在代码中使用cartesianProduct
几次才有用。
List<Pair<A, B>> pairs = as.stream().collect(cartesianProduct(bs));
public static <T1, T2> Collector<T1, ?, List<Pair<T1, T2>>>
cartesianProduct(Collection<T2> other)
{
return Collector.of(
ArrayList::new,
(list, a) -> list.addAll(
other.stream().map(b -> new Pair(a, b))).collect(Collectors.toList())),
(list1, list2) ->
{
list1.addAll(list2);
return list1;
},
Collector.Characteristics.UNORDERED
);
}
注意:我是Eclipse Collections的提交者。