给定
ArrayList
的 ['A','a','B','C','C']
,则重复项为 ['A','a','C','C']
,非重复项为 ['B']
。
我试过了:
Map<String, Long> counts = nums.parallelStream()
.collect( Collectors.groupingBy( {k -> k.toLowerCase()}, Collectors.counting()) )
它给出计数:{a:2, b:1, c:2}
现在我正在寻找重复和非重复,我目前正在使用下面的代码进行操作:
Map<Boolean, List<String>> hasDup =
counts.entrySet().parallelStream()
.collect(Collectors.partitioningBy(
entry -> entry.getValue() > 1,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
List<String> dup = hasDup.get(true);
List<String> nodup = hasDup.get(false);
dup: ['a','c'] nondups: ['b']
我需要帮助,因为预期的输出与我想要的不一样:
dups: ['A','a','C','C'] nondups: ['B']
如何解决这个问题,通过修复我的代码或替代解决方案?
看起来你正在混合东西,因为即使它是非并行流,算法也不会返回你想要的东西。 在第二部分中,您将获得由于重复计数而用于分组的密钥,该密钥也是小写的。所以,你不会检索到大写的。
然后,您真正需要的是将重复项“展开”与相关计数相同的次数。
List<Character> nums = List.of('A' , 'a' , 'B' , 'C' , 'C');
Map<String, Long> counts = nums.parallelStream()
.map(String::valueOf)
.collect(Collectors.groupingBy(String::toLowerCase, Collectors.counting()));
List<Character> dup = new ArrayList<>();
List<Character> nodup = new ArrayList<>();
nums.forEach(x -> (counts.get(x.toString().toLowerCase()) > 1 ? dup : nodup).add(x));
然后,由于它迭代
nums
来填充 dup
和 nodup
列表,因此您拥有原始的角色。
正如 Leo 指出的那样,第一部分并没有受益于并行性,因为工作几乎全部发生在收集器中。 这可能也适用于第二部分。
....或解决此问题的替代建议:
我认为如果不使用流,您将获得明显更好的性能。 相反,手动对输入进行分区,并将分区分配给 N 个线程,以使用 key -> count 条目填充 shared
ConcurrentHashMap
。
此外,我认为您需要重新考虑表示此过程输出的方式。 令我印象深刻的是,生成包含多个重复项副本的列表是不必要的且效率低下。 甚至将重复项与非重复项分开似乎也没有必要。 不要生成列表,而是查看是否可以更改下游代码以直接从
Map
传输数据。 或者将数据推送到并发队列中,供多个下游工作线程消费。
观察:为了有效地利用并行性来解决问题,通常需要改变问题。