通过 Streams API 比较集合中元素的所有组合
Posted
技术标签:
【中文标题】通过 Streams API 比较集合中元素的所有组合【英文标题】:Comparing all combinations of elements in a Collection via the Streams API 【发布时间】:2021-12-30 09:13:42 【问题描述】:我正在尝试比较 HashMap
中元素的所有组合(即没有重复比较),并返回满足 HashMap 的所有元素的列表
比较函数,使用 Java 8 Streams-API。
即我想要这样的东西:
// pseudo code, this isnt hashmaps work but hopefully it gets the point across
for(int i=0; i<myHashMap.entrySet().length, i++)
for(int j=i+1, j<myHashMap.entrySet().length)
if(myComparison(entrySet.get(i), entrySet.get(j)))
myList.add(new myClass[] entrySet.get(i), entrySet.get(j))
但使用流 API。我有一个几乎可以使用.forEach
并简单地迭代流两次的版本,但是这存在运行重复比较的问题,从而将这些重复项再次添加到列表中。我相当确定 reduce
操作员能够做到我
需要,但我完全不熟悉 Streams API,无法弄清楚如何达到预期的结果。
【问题讨论】:
如果我正确理解了这个问题,您可以从地图中构建一个集合以删除重复项,然后从集合中构建一个列表。 @Alex 不,重复项是因为与[a, b, c]
一起比较了a, b
和b, a
,这可能会产生相同的结果比较它们。在命令式版本中避免了这种情况,因为j
从i+1
开始,因此它只遍历其余元素,但是.forEach
总是遍历所有元素。一组不只是修复它,OP 比较所有独特的对。
【参考方案1】:
您需要生成地图的 n 个条目/键的所有不同 k 组合。这篇文章展示了如何实现这样的算法java-combinations-algorithm。但由于我认为任务不是提出这样的算法,我建议使用一个为你完成这项任务的库。这样的库之一是combinatoricslib3。如果你碰巧已经在使用 Apache Commons 或 Guava,它们也有实现组合。
使用 combinatoricslib3 您的代码可能如下所示:
import java.util.Map;
import org.paukov.combinatorics3.Generator;
public class TestJavaClass
public static void main(String[] args)
Map<String,Integer> myMap = Map.of("Foo", 1, "Bar", 2, "Baz", 3);
Generator.combination(myMap.keySet())
.simple(2)
.stream()
.forEach(System.out::println);
输出:
[Foo, Baz]
[Foo, Bar]
[Baz, Bar]
我使用上面的键组来展示一个简单的例子。但如果您需要这些条目,您可以将其更改为:
Generator.combination(myMap.entrySet())...
获取条目组合:
[Foo=1, Baz=3]
[Foo=1, Bar=2]
[Baz=3, Bar=2]
不确定您的 myComparison
方法是做什么的,但由于您将它用作 if 语句中的条件,我假设它返回一个布尔值。如果是这样,您可以将其用作过滤器以进一步处理流。使用您的方法 myComparison
和自定义类 MyClass
的虚拟实现,如下所示应该为您提供一个起点:
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.paukov.combinatorics3.Generator;
import lombok.AllArgsConstructor;
public class TestJavaClass
public static void main(String[] args)
Map<String, Integer> myMap = Map.of("Foo", 1, "Bar", 2, "Baz", 3);
List<MyClass> result =
Generator.combination(myMap.entrySet())
.simple(2)
.stream()
.filter(comb -> myComparison(comb.get(0), comb.get(1)))
.map(comb -> new MyClass(comb.get(0), comb.get(1)))
.collect(Collectors.toList());
static boolean myComparison(Map.Entry<String, Integer> first, Map.Entry<String, Integer> second)
return first.getValue() + second.getValue() <= 4;
@AllArgsConstructor
static class MyClass
Map.Entry<String, Integer> one;
Map.Entry<String, Integer> two;
【讨论】:
我在这个网站上收到的最佳答案,非常感谢您提供的丰富信息! 不客气。我很高兴能帮上忙。以上是关于通过 Streams API 比较集合中元素的所有组合的主要内容,如果未能解决你的问题,请参考以下文章