繁体   English   中英

使用流在列表中查找具有最大出现次数的键

[英]To use streams to find keys in a list with max occurance

我们有一个列表:

List<String> strList = Arrays.asList("10.0 string1", "10.3 string2", "10.0 string3", "10.4 string4","10.3 string5");

每个条目都是一个由 2 个由空格分隔的字符串组成的字符串。 目标是找到所有出现次数最多的条目(即出现 2 次的 10.0 和 10.3)。

以下代码有效。 问题是这 3 个陈述可以减少到 1 个或至少 2 个吗?

var map2 = strList.stream()
                  .map(m -> {String[] parts = m.split(" "); return parts[0];})
                  .collect((Collectors.groupingBy(Function.identity(),LinkedHashMap::new, Collectors.counting())));

var max3 = map2.entrySet().stream()
               .max((entry1, entry2) -> entry1.getValue() > entry2.getValue() ? 1 : -1) 
               .get() 
               .getValue();

var listOfMax2 = map2.entrySet().stream()
                     .filter(entry -> entry.getValue() == max3)
                     .map(Map.Entry::getKey)
                     .collect(Collectors.toList());

System.out.println(listOfMax2);

如果您将变量的名称更改为有意义的名称,那么您拥有的代码非常简单。 您可以编写一个自定义收集器,但我怀疑它是否值得付出努力,并且能够使您的代码更具可读性。 我能想到的最简单的解决方案是,如果你坚持链接你的 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ,首先建立频率然后反转 map 以使用值(频率)作为键和键作为值并收集到树形图,这是排序的按键,并获取最后一个条目:

List<String> strList = Arrays.asList("10.0 string1", "10.3 string2", "10.0 string3", "10.4 string4", "10.3 string5");

var mostFrequentEntries =
        strList.stream()
               .map(s -> s.substring(0, s.indexOf(' ')))
               .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
               .entrySet()
               .stream()
               .collect(Collectors.groupingBy(Map.Entry::getValue, TreeMap::new, Collectors.mapping(Map.Entry::getKey, Collectors.toList())))
               .lastEntry().getValue();

System.out.println(mostFrequentEntries);
strList
    .stream()
    .map(s -> s.substring(0, s.indexOf(" ")))
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .entrySet()
    .stream()
    .collect(Collectors.groupingBy(Entry::getValue))
    .entrySet()
    .stream()
    .max(Entry.comparingByKey())
    .ifPresentOrElse(longListEntry -> longListEntry.getValue().stream().map(Entry::getKey).forEach(System.out::println),
                     () -> System.out.println("No Value Found"));

印刷:

10.3
10.0

非常坦率的:

  1. 使用Stream#map获取密钥。
  2. 使用Collectors#groupingBy将密钥的频率作为Map获取。
  3. 将所有相同的频率组合在一起。
  4. 获取Stream#max频率并在O(n)时间内打印List

我知道的这种最简单的方法是从目标值的频率计数开始,并在数据结构中返回最大值和 map 以供后续处理。

这是一些数据(添加到您的演示中)

List<String> strList = Arrays.asList("10.0 string1",
        "10.0 string2", "10.3 string3", "10.0 string4",
        "10.3 string5", "10.4 string 6", "10.3 string7",
        "10.4 string8", "10.5 string 9", "10.6 string10");
  • 首先,stream 列表并根据频率创建 map。 这是通过使用toMap并增加重复键的计数来完成的。

  • 然后 stream 该 map 的条目寻找最大计数。 然后在SimpleEntry数据结构中返回计数和 map。

Entry<Integer,Map<String,Integer>> result =  strList.stream()
            .map(str -> str.split("\\s+")[0]).
            collect(Collectors.collectingAndThen(
                    Collectors.toMap(s -> s, s -> 1,Integer::sum),
                    m -> new SimpleEntry<>(m.entrySet()
                    .stream()
                    .map(Entry::getValue)
                    .max(Integer::compare).orElse(0),m)));
  • 现在,使用返回的 map 和最大计数,打印所有具有相同计数的键。
int max = result.getKey();
result.getValue().forEach((k,v)-> {
    if (v == max) {
        System.out.println(k);
    }
});

印刷

10.4
10.3
10.0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM