簡體   English   中英

我應該使用Java 8 Streams Api來組合兩個集合嗎?

[英]Should I use Java 8 Streams Api to combine two Collections?

我有這種情況,似乎Java 8 Streams API會有所幫助,但我不完全確定它是怎么回事。

從兩個集合具有鮮明的元素類型,我想建立第三集合的元素是從兩個集合元素的所有可能的對 基本上:

兩種截然不同的元素類型......

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只是可變縮減的一個示例。

有更優雅的方式嗎? 或者更可取的是,在效率方面以更有利可圖的方式? 就像是

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

我希望我沒有任何愚蠢的錯別字,但基本上你可以做的是:

List<Pair> list = as
                  .stream()
                  .flatMap(a -> bs.stream().map (b -> new Pair(a,b)))
                  .collect (Collectors.toList());
  1. 首先,您從as創建一個Stream<A>
  2. 對於每a實例
    2.1創建bsStream<B>
    2.2將每個b映射到一對(a,b)
  3. 將所有對平展為單個流。
  4. 最后我將它們收集到List中,但您可以選擇其他集合。

如果您願意使用第三方庫,則可以使用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 flatCollectcollect ,這相當於flatMapmap上的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另一個可能選項是為cartesianProduct定義自己的Collector 這比其他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的提交者。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM