您可以使用递归链解决此问题。flatMap
首先,由于我们需要通过映射值来回移动,因此最好将它们复制到(这不是深度副本,在您的情况下,它只有3个元素,因此额外的内存使用率很低)。ArrayListArrayList
其次,为了维护以前访问过的元素的前缀,让我们创建一个帮助器不可变类:Prefix
private static class Prefix<T> {
    final T value;
    final Prefix<T> parent;
    Prefix(Prefix<T> parent, T value) {
        this.parent = parent;
        this.value = value;
    }
    // put the whole prefix into given collection
    <C extends Collection<T>> C addTo(C collection) {
        if (parent != null)
            parent.addTo(collection);
        collection.add(value);
        return collection;
    }
}
这是一个非常简单的不可变链表,可以这样使用:
List<String> list = new Prefix<>(new Prefix<>(new Prefix<>(null, "a"), "b"), "c")
                          .addTo(new ArrayList<>()); // [a, b, c];
接下来,让我们创建链接 flatMaps 的内部方法:
private static <T, C extends Collection<T>> Stream<C> comb(
        List<? extends Collection<T>> values, int offset, Prefix<T> prefix,
        Supplier<C> supplier) {
    if (offset == values.size() - 1)
        return values.get(offset).stream()
                     .map(e -> new Prefix<>(prefix, e).addTo(supplier.get()));
    return values.get(offset).stream()
            .flatMap(e -> comb(values, offset + 1, new Prefix<>(prefix, e), supplier));
}
看起来像递归,但它更复杂:它不直接调用自己,而是传递了调用外部方法的lambda。参数:
- 值:原始值(在您的情况下)。
Listnew ArrayList<>(map.values) 
- 偏移量:此列表中的当前偏移量
 
- 前缀:长度偏移量的当前前缀(或 if )。它包含集合中当前选定的元素,直到 。
nulloffset == 0list.get(0)list.get(1)list.get(offset-1) 
- supplier:创建结果集合的工厂方法。
 
当我们到达值列表()的末尾时,我们使用供应商将最后一个集合的元素从值映射到最终组合。否则,我们对每个中间元素使用what来放大前缀,并为下一个偏移量再次调用该方法。offset == values.size() - 1flatMapcomb
最后,下面是使用此功能的公共方法:
public static <T, C extends Collection<T>> Stream<C> ofCombinations(
        Collection<? extends Collection<T>> values, Supplier<C> supplier) {
    if (values.isEmpty())
        return Stream.empty();
    return comb(new ArrayList<>(values), 0, null, supplier);
}
用法示例:
Map<String, Collection<String>> map = new LinkedHashMap<>(); // to preserve the order
map.put("A", Arrays.asList("a1", "a2", "a3", "a4"));
map.put("B", Arrays.asList("b1", "b2", "b3"));
map.put("C", Arrays.asList("c1", "c2"));
ofCombinations(map.values(), LinkedHashSet::new).forEach(System.out::println);
我们再次收集单个组合以保持顺序。您可以使用任何其他集合(例如 )。LinkedHashSetArrayList::new