簡體   English   中英

創建元素的所有可能組合

[英]Create all possible combinations of elements

我需要創建某種鍵的所有可能組合,這些鍵由同樣重要的X(在我的情況下為8)組成。 所以我想出了這樣的代碼:

final LinkedList<Key> keys = new LinkedList();

firstElementCreator.getApplicableElements() // All creators return a Set of elements
          .forEach( first -> secondElementCreator.getApplicableElements()
           .forEach( second -> thirdElementCreator.getApplicableElements()
            // ... more creators
           .forEach( X -> keys.add( new Key( first, second, third, ..., X ) ) ) ) ) ) ) ) );

return keys;

並且它正在工作,但是有X嵌套的forEach,我感覺缺少了一個更簡單/更好/更優雅的解決方案。 有什么建議么? 提前致謝!

它是笛卡爾積嗎? 許多庫都提供API,例如:Guava中的SetsLists

List<ApplicableElements> elementsList = Lists.newArrayList(firstElementCreator, secondElementCreator...).stream()
        .map(c -> c.getApplicableElements()).collect(toList());

List<Key> keys = Lists.cartesianProduct(elementsList).stream()
        .map(l -> new Key(l.get(0), l.get(1), l.get(2), l.get(3), l.get(4), l.get(5), l.get(6), l.get(7))).collect(toList());

由於輸入集的數量是固定的(必須與Key構造函數中的參數數量匹配),所以您的解決方案實際上還不錯。

但是,無需使用lambda,它會更高效,更容易閱讀,例如:

for (Element first : firstElementCreator.getApplicableElements()) {
    for (Element second : secondElementCreator.getApplicableElements()) {
        for (Element third : thirdElementCreator.getApplicableElements()) {
            keys.add(new Key(first, second, third));
        }
    }
}

規范的解決方案是使用flatMap 但是,棘手的部分是從多個輸入級別創建Key對象。

簡單的方法是在最內層的函數中進行評估,其中每個值都在范圍內

final List<Key> keys = firstElementCreator.getApplicableElements().stream()
  .flatMap(first -> secondElementCreator.getApplicableElements().stream()
    .flatMap(second -> thirdElementCreator.getApplicableElements().stream()
      // ... more creators
      .map( X -> new Key( first, second, third, ..., X ) ) ) )
  .collect(Collectors.toList());

但這很快就不能用於深層嵌套

沒有深層嵌套的解決方案需要元素保留中間復合值。 例如,如果我們將Key定義為

class Key {
    String[] data;
    Key(String... arg) {
        data=arg;
    }
    public Key add(String next) {
        int pos = data.length;
        String[] newData=Arrays.copyOf(data, pos+1);
        newData[pos]=next;
        return new Key(newData);
    }

    @Override
    public String toString() {
        return "Key("+Arrays.toString(data)+')';
    }
}

(假設String為元素類型),我們可以使用

final List<Key> keys =
    firstElementCreator.getApplicableElements().stream().map(Key::new)
      .flatMap(e -> secondElementCreator.getApplicableElements().stream().map(e::add))
      .flatMap(e -> thirdElementCreator.getApplicableElements().stream().map(e::add))
      // ... more creators
      .collect(Collectors.toList());

注意,這些flatMap步驟現在處於同一級別,即不再嵌套。 同樣,所有這些步驟都是相同的,只是實際的創建者有所不同,這導致支持任意數量的Creator實例的通用解決方案。

List<Key> keys = Stream.of(firstElementCreator, secondElementCreator, thirdElementCreator
                           /* , and, some, more, if you like */)
    .map(creator -> (Function<Key,Stream<Key>>)
                    key -> creator.getApplicableElements().stream().map(key::add))
    .reduce(Stream::of, (f1,f2) -> key -> f1.apply(key).flatMap(f2))
    .apply(new Key())
    .collect(Collectors.toList());

在這里,每個創建者都映射到與前一個解決方案相同的流生成函數,然后將所有簡化為單個函數,並將每個函數與flatMap步驟組合到下一個函數,最后執行結果函數以獲取流,然后將其收集到List

暫無
暫無

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

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