当前位置: 首页 > 知识库问答 >
问题:

字频计数Java 8

易风华
2023-03-14

如何统计列表在Java8中的单词频率?

List <String> wordsList = Lists.newArrayList("hello", "bye", "ciao", "bye", "ciao");

结果必须是:

{ciao=2, hello=1, bye=2}

共有3个答案

融伯寅
2023-03-14

使用泛型查找集合中最常见的项目:

private <V> V findMostFrequentItem(final Collection<V> items)
{
  return items.stream()
      .filter(Objects::nonNull)
      .collect(Collectors.groupingBy(Functions.identity(), Collectors.counting()))
      .entrySet()
      .stream()
      .max(Comparator.comparing(Entry::getValue))
      .map(Entry::getKey)
      .orElse(null);
}

计算项目频率:

private <V> Map<V, Long> findFrequencies(final Collection<V> items)
{
  return items.stream()
      .filter(Objects::nonNull)
      .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}
上官凯歌
2023-03-14

(注意:请参阅下面的编辑)

作为Mounas答案的另一种选择,这里有一种平行计算单词的方法:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ParallelWordCount
{
    public static void main(String[] args)
    {
        List<String> list = Arrays.asList(
            "hello", "bye", "ciao", "bye", "ciao");
        Map<String, Integer> counts = list.parallelStream().
            collect(Collectors.toConcurrentMap(
                w -> w, w -> 1, Integer::sum));
        System.out.println(counts);
    }
}

EDIT作为对评论的回应,我使用JMH进行了一个小测试,比较了toConconttMapgroupingByCon电流方法,不同的输入列表大小和不同长度的随机单词。这个测试表明toCon电流tMap方法更快。当考虑到这些方法“在幕后”有多么不同时,很难预测这样的事情。

作为进一步的扩展,基于进一步的评论,我扩展了测试以涵盖toMapgroupingBy、串行和并行的所有四种组合。

结果仍然是,toMap方法更快,但出乎意料的是(至少对我来说)“并发”版本在这两种情况下都比串行版本慢……:

             (method)  (count) (wordLength)  Mode  Cnt     Score    Error  Units
      toConcurrentMap     1000            2  avgt   50   146,636 ±  0,880  us/op
      toConcurrentMap     1000            5  avgt   50   272,762 ±  1,232  us/op
      toConcurrentMap     1000           10  avgt   50   271,121 ±  1,125  us/op
                toMap     1000            2  avgt   50    44,396 ±  0,541  us/op
                toMap     1000            5  avgt   50    46,938 ±  0,872  us/op
                toMap     1000           10  avgt   50    46,180 ±  0,557  us/op
           groupingBy     1000            2  avgt   50    46,797 ±  1,181  us/op
           groupingBy     1000            5  avgt   50    68,992 ±  1,537  us/op
           groupingBy     1000           10  avgt   50    68,636 ±  1,349  us/op
 groupingByConcurrent     1000            2  avgt   50   231,458 ±  0,658  us/op
 groupingByConcurrent     1000            5  avgt   50   438,975 ±  1,591  us/op
 groupingByConcurrent     1000           10  avgt   50   437,765 ±  1,139  us/op
      toConcurrentMap    10000            2  avgt   50   712,113 ±  6,340  us/op
      toConcurrentMap    10000            5  avgt   50  1809,356 ±  9,344  us/op
      toConcurrentMap    10000           10  avgt   50  1813,814 ± 16,190  us/op
                toMap    10000            2  avgt   50   341,004 ± 16,074  us/op
                toMap    10000            5  avgt   50   535,122 ± 24,674  us/op
                toMap    10000           10  avgt   50   511,186 ±  3,444  us/op
           groupingBy    10000            2  avgt   50   340,984 ±  6,235  us/op
           groupingBy    10000            5  avgt   50   708,553 ±  6,369  us/op
           groupingBy    10000           10  avgt   50   712,858 ± 10,248  us/op
 groupingByConcurrent    10000            2  avgt   50   901,842 ±  8,685  us/op
 groupingByConcurrent    10000            5  avgt   50  3762,478 ± 21,408  us/op
 groupingByConcurrent    10000           10  avgt   50  3795,530 ± 32,096  us/op

我对JMH不太有经验,也许我在这里做错了什么——欢迎提出建议和更正:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Blackhole;

@State(Scope.Thread)
public class ParallelWordCount
{

    @Param({"toConcurrentMap", "toMap", "groupingBy", "groupingByConcurrent"})
    public String method;

    @Param({"2", "5", "10"})
    public int wordLength;

    @Param({"1000", "10000" })
    public int count;

    private List<String> list;

    @Setup
    public void initList()
    {
         list = createRandomStrings(count, wordLength, new Random(0));
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void testMethod(Blackhole bh)
    {

        if (method.equals("toMap"))
        {
            Map<String, Integer> counts =
                list.stream().collect(
                    Collectors.toMap(
                        w -> w, w -> 1, Integer::sum));
            bh.consume(counts);
        }
        else if (method.equals("toConcurrentMap"))
        {
            Map<String, Integer> counts =
                list.parallelStream().collect(
                    Collectors.toConcurrentMap(
                        w -> w, w -> 1, Integer::sum));
            bh.consume(counts);
        }
        else if (method.equals("groupingBy"))
        {
            Map<String, Long> counts =
                list.stream().collect(
                    Collectors.groupingBy(
                        Function.identity(), Collectors.<String>counting()));
            bh.consume(counts);
        }
        else if (method.equals("groupingByConcurrent"))
        {
            Map<String, Long> counts =
                list.parallelStream().collect(
                    Collectors.groupingByConcurrent(
                        Function.identity(), Collectors.<String> counting()));
            bh.consume(counts);
        }
    }

    private static String createRandomString(int length, Random random)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++)
        {
            int c = random.nextInt(26);
            sb.append((char) (c + 'a'));
        }
        return sb.toString();
    }

    private static List<String> createRandomStrings(
        int count, int length, Random random)
    {
        List<String> list = new ArrayList<String>(count);
        for (int i = 0; i < count; i++)
        {
            list.add(createRandomString(length, random));
        }
        return list;
    }
}

时间仅与包含10000个元素和两个字母单词的列表的连续情况相似。

检查对于更大的列表大小,并发版本是否最终优于串行版本可能是值得的,但目前没有时间使用所有这些配置运行另一个详细的基准测试。

祖新觉
2023-03-14

我想分享我找到的解决方案,因为起初我希望使用map和reduce方法,但有点不同。

Map<String,Long> collect = wordsList.stream()
    .collect( Collectors.groupingBy( Function.identity(), Collectors.counting() ));

或对于整数值:

Map<String,Integer> collect = wordsList.stream()
     .collect( Collectors.groupingBy( Function.identity(), Collectors.summingInt(e -> 1) ));

编辑

我添加了如何按值对地图进行排序:

LinkedHashMap<String, Long> countByWordSorted = collect.entrySet()
            .stream()
            .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
            .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    Map.Entry::getValue,
                    (v1, v2) -> {
                        throw new IllegalStateException();
                    },
                    LinkedHashMap::new
            ));
 类似资料:
  • 问题内容: 我有一张表,上面有像 我想做一张像这样的桌子 等等。 问题答案: WITH basedata(id,keywords) AS ( SELECT 1,’cat, dog, man, mouse’ union all SELECT 2 ,’man, pen, pencil, eraser’ union all SELECT 3,’dog, man, friends’ union all S

  • 给定 我想使用Java8流像下面这样打印 。 使用以下内容: 但不起作用。

  • 问题内容: 这是Python和NLTK新手问题。 我想查找双峰发生的频率,这些双峰发生在一起的次数超过10次,并且具有最高的PMI。 为此,我正在使用此代码 但是,这并不会将结果限制在前20位。我看到的结果的频率小于10。我是Python世界中的新手。 有人可以指出如何修改它以仅获得前20名。 谢谢 问题答案: 问题在于您尝试使用的方式。我们正在讨论单词搭配。如您所知,单词搭配是关于单词之间的依赖

  • 1. 自我介绍 2. 经历相关(几段实习之间差别还挺大的,为什么这么选择?互相之间可以借鉴吗?未来更想做什么行业) 3. 一共讲了四个项目,第一个UIUX都有(不太感兴趣),第二个上线小功能迭代(为什么其中一个数据会比较好),第三个讲了笔试题(从头讲到尾),第四个讲了适老化设计(因为更想听一些交互向 系统性的的回答) 4. 反问了一些工作内容

  • 问题内容: 我需要编写某种循环,可以计算字符串中每个字母的频率。 例如:“ aasjjikkk”将计为2’a’,1’s’,2’j’,1’i’,3’k’。最终,像这样的id最终以字符为键,而count为值的形式出现在地图中。有什么好主意怎么做? 问题答案: 你可以使用Java Map并将a映射到。然后,你可以遍历字符串中的字符,并检查是否已将它们添加到地图中(如果有),然后可以增加其值。 例如: 最

  • 问题内容: 这是来自pyschools的问题。 我确实做对了,但我猜测会有一个更简单的方法。这是最简单的方法吗? 看起来应该像这样: 问题答案: 在2.7+中: 较早的版本(2.5或更高版本,到目前为止):