[英]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中的Sets和Lists :
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.