创建重复计数映射后如何优化此重复查找代码

问题描述 投票:0回答:2

给定

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']

如何解决这个问题,通过修复我的代码或替代解决方案?

java string dictionary parallel-processing java-stream
2个回答
1
投票

看起来你正在混合东西,因为即使它是非并行流,算法也不会返回你想要的东西。 在第二部分中,您将获得由于重复计数而用于分组的密钥,该密钥也是小写的。所以,你不会检索到大写的。

然后,您真正需要的是将重复项“展开”与相关计数相同的次数。

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
列表,因此您拥有原始的角色。


1
投票

正如 Leo 指出的那样,第一部分并没有受益于并行性,因为工作几乎全部发生在收集器中。 这可能也适用于第二部分。

....或解决此问题的替代建议:

我认为如果不使用流,您将获得明显更好的性能。 相反,手动对输入进行分区,并将分区分配给 N 个线程,以使用 key -> count 条目填充 shared

ConcurrentHashMap

此外,我认为您需要重新考虑表示此过程输出的方式。 令我印象深刻的是,生成包含多个重复项副本的列表是不必要的且效率低下。 甚至将重复项与非重复项分开似乎也没有必要。 不要生成列表,而是查看是否可以更改下游代码以直接从

Map
传输数据。 或者将数据推送到并发队列中,供多个下游工作线程消费。


观察:为了有效地利用并行性来解决问题,通常需要改变问题。

© www.soinside.com 2019 - 2024. All rights reserved.