如果列表中某个项目出现多次,则删除该项目的所有实例

Rob*_*son 2 java collections data-structures java-8 java-stream

给定一个数字列表: { 4, 5, 7, 3, 5, 4, 2, 4 }

所需的输出是: { 7, 3, 2 }

我正在考虑的解决方案是从给定的列表中在 HashMap 下创建:

Map<Integer, Integer> numbersCountMap = new HashMap();
Run Code Online (Sandbox Code Playgroud)

其中键是列表中的值,值是出现次数。

然后循环遍历 HashMap 条目集,只要数字包含的计数大于 1,就从列表中删除该数字。

for (Map.Entry<Int, Int> numberCountEntry : numbersCountMap.entrySet()) {
     if(numberCountEntry.getValue() > 1) {  
        testList.remove(numberCountEntry.getKey());
     }
}
Run Code Online (Sandbox Code Playgroud)

我不确定这是否是解决此问题的有效方法,因为remove(Integer)对列表的操作可能很昂贵。此外,我正在创建额外的 Map 数据结构。并循环两次,一次在原始列表上创建地图,然后在地图上删除重复项。

你能不能提出一个更好的方法。可能是 Java 8 有更好的实现方式。我们还可以在 Java 8 中使用 Streams 和其他新结构在几行中完成吗?

YCF*_*F_L 5

通过流,您可以使用:

Map<Integer, Long> grouping = integers.stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
grouping.values().removeIf(c -> c > 1);
Set<Integer> result = grouping.keySet();
Run Code Online (Sandbox Code Playgroud)

或者正如@Holger 所提到的,您只想知道列表中是否有多个整数,所以只需执行以下操作:

Map<Integer, Boolean> grouping = integers.stream()
        .collect(Collectors.toMap(Function.identity(),
                x -> false, (a, b) -> true,
                HashMap::new));
grouping.values().removeIf(b -> b);
// or
grouping.values().removeAll(Collections.singleton(true));
Set<Integer> result = grouping.keySet();
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这些收集器不保证返回的映射是可变的,因此您应该使用具有显式映射工厂的变体。此外,您不需要计算出现次数,您只想知道是否存在多个: `Map&lt;Integer, Boolean&gt; grouping = integers.stream() .collect(Collectors.toMap(Function.identity) (), x -&gt; false, (a,b) -&gt; true, HashMap::new));`,后跟 `grouping.values().removeIf(b -&gt; b);` 或 `grouping。 value().removeAll(Collections.singleton(true));`。在所有元素上循环执行“indexOf”会产生 O(n²),所以不要这样做。 (5认同)