Java 创建所有可能的元素组合
我需要创建一些键的所有可能组合,这些键由X(在我的例子中是8)组成,这些元素同样重要。所以我想出了这样的代码:Java 创建所有可能的元素组合,java,algorithm,performance,java-stream,Java,Algorithm,Performance,Java Stream,我需要创建一些键的所有可能组合,这些键由X(在我的例子中是8)组成,这些元素同样重要。所以我想出了这样的代码: final LinkedList<Key> keys = new LinkedList(); firstElementCreator.getApplicableElements() // All creators return a Set of elements .forEach( first -> secondElementCreator.ge
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;
final LinkedList key=new LinkedList();
firstElementCreator.GetApplicatableElements()//所有创建者都返回一组元素
.forEach(first->secondElementCreator.getApplicatableElements()
.forEach(第二->第三个delementCreator.getApplicatableElements()
//…更多的创造者
.forEach(X->keys.add(新键(第一、第二、第三、…、X)));
返回键;
它正在工作,但是有X嵌套的forEach,我觉得我错过了一个更简单/更好/更优雅的解决方案。有什么建议吗?
提前谢谢 是笛卡尔积吗?许多库提供API,例如:和Guava:
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());
List elementsList=Lists.newArrayList(firstElementCreator,secondElementCreator…).stream()
.map(c->c.getApplicatableElements()).collect(toList());
列表键=Lists.cartesianProduct(elementsList.stream())
.map(l->newkey(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());
是笛卡尔积吗?许多库提供API,例如:和Guava:
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());
List elementsList=Lists.newArrayList(firstElementCreator,secondElementCreator…).stream()
.map(c->c.getApplicatableElements()).collect(toList());
列表键=Lists.cartesianProduct(elementsList.stream())
.map(l->newkey(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());
由于输入集的数量是固定的(它必须与密钥构造函数中的参数数量相匹配),因此您的解决方案实际上是不错的
但是,如果没有lambdas,它会更高效、更容易阅读,比如:
for (Element first : firstElementCreator.getApplicableElements()) {
for (Element second : secondElementCreator.getApplicableElements()) {
for (Element third : thirdElementCreator.getApplicableElements()) {
keys.add(new Key(first, second, third));
}
}
}
由于输入集的数量是固定的(它必须与键构造函数中的参数数量相匹配),因此您的解决方案实际上是不错的 但是,如果没有lambdas,它会更高效、更容易阅读,比如:
for (Element first : firstElementCreator.getApplicableElements()) {
for (Element second : secondElementCreator.getApplicableElements()) {
for (Element third : thirdElementCreator.getApplicableElements()) {
keys.add(new Key(first, second, third));
}
}
}
规范的解决方案是使用
flatMap
。然而,棘手的部分是从多个输入级别创建键
对象
直接的方法是在最内部的函数中进行计算,其中每个值都在范围内
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());
(假设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
步骤组合到下一个步骤,最后执行生成的函数以获得流,然后将其收集到列表中
标准解决方案是使用flatMap
。然而,棘手的部分是从多个输入级别创建键
对象
直接的方法是在最内部的函数中进行计算,其中每个值都在范围内
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());
(假设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
步骤组合到下一个步骤,最后执行生成的函数以获得流,当你需要任意数量的循环时,递归几乎总是答案。当你需要任意数量的循环时,递归几乎总是答案。这是我一直在寻找的答案。尽管如此,这个解决方案还是有一个缺点:我的每个元素都有不同的类型(现在我知道我没有提到),所以类型转换是必要的。也许可以创建一些公共接口,我会考虑一下。谢谢。这是我一直在寻找的答案。尽管如此,这个解决方案还是有一个缺点:我的每个元素都有不同的类型(现在我知道我没有提到),所以类型转换是必要的。也许可以创建一些公共接口,我会考虑一下。谢谢。你是对的,流并不总是最好的解决方案,这看起来肯定更好,谢谢。你是对的,流并不总是最好的解决方案,这看起来肯定更好,谢谢。