【问题标题】:Counting occurrences of values of items inside a List within a Hash<String,List<String>>计算 Hash<String,List<String>> 中 List 内项目值的出现次数
【发布时间】:2016-06-11 18:09:22
【问题描述】:

我有一个哈希结构 hash_feat &lt;String, List&lt;String&gt;&gt;,其中我的 keysYears 并且里面的 values 列表有一个不同术语的列表。

我已经有了我的哈希值,即来自特定 key 的所有项目都在该键的同一个列表中,例如:

<1997> <A,B,C,A,A,A,B,C,C,E> <2003> <C,C,C,A,B,A,D,D,D,A> <2004> <A,C,C,X,X,A,K,T,T,T>

我想对每个项目进行计数。对于 1997 年的 A:4、B:2、C:3、E:1 以此类推,其他以此类推。

我试图想出这个来使用这个“计数”来稍后显示在一个图中,我可以在其中可视化图表中每个项目的最高计数。可能这不是最聪明的方法,所以这里的任何建议也将受到欢迎。这个想法是在我的列表中列出每个项目的数量,以便我可以在其他方法中操作/使用。

任何人有一个很好的建议,以聪明的方式做到这一点?

【问题讨论】:

  • Guava Multiset 是一个很好的计数工具。另请参阅Multisets 中的 utils

标签: java list hash hashmap counting


【解决方案1】:

Eclipse Collections 中有一个名为BagMultimap 的数据结构可以很好地适用于您的用例。以下是如何将 MutableBagMultimap 用于您的示例数据。

MutableBagMultimap<String, String> multimap = Multimaps.mutable.bag.empty();
multimap.putAll("1997", Lists.mutable.with("A","B","C","A","A","A","B","C","C","E"));
multimap.putAll("2003", Lists.mutable.with("C","C","C","A","B","A","D","D","D","A"));
multimap.putAll("2004", Lists.mutable.with("A","C","C","X","X","A","K","T","T","T"));

Assert.assertEquals(4, multimap.get("1997").occurrencesOf("A"));
Assert.assertEquals(2, multimap.get("1997").occurrencesOf("B"));
Assert.assertEquals(3, multimap.get("1997").occurrencesOf("C"));
Assert.assertEquals(1, multimap.get("1997").occurrencesOf("E"));

您可以简单地使用forEachKeyMultivaluestoStringOfItemToCount 输出多图。

multimap.forEachKeyMultiValues((key, values) ->
    System.out.println("<" + key + "> " + ((Bag<String>)values).toStringOfItemToCount()));

此代码显示以下内容:

<1997> {E=1, A=4, B=2, C=3}
<2004> {T=3, A=2, C=2, X=2, K=1}
<2003> {D=3, A=3, B=1, C=3}

或者您可以使用forEachWithOccurrences 编写以下代码来控制输出。

multimap.forEachKey(key -> {
    System.out.print(key + " ");
    multimap.get(key).forEachWithOccurrences((value, occurrences) ->
        System.out.print(value + ":" + occurrences + " "));
    System.out.println();
});

此代码显示以下内容:

1997 E:1 A:4 B:2 C:3 
2004 T:3 A:2 C:2 X:2 K:1 
2003 D:3 A:3 B:1 C:3  

最后,您可以使用topOccurrences,如果您希望输出按出现次数最多到最少的顺序排列。

multimap.forEachKey(key -> {
    System.out.print(key + " ");
    MutableBag<String> bag = multimap.get(key);
    bag.topOccurrences(bag.sizeDistinct())
        .each(pair ->
            System.out.print(pair.getOne() + ":" + pair.getTwo() + " "));
    System.out.println();
});

此代码显示以下内容:

1997 A:4 C:3 B:2 E:1 
2004 T:3 A:2 C:2 X:2 K:1 
2003 D:3 A:3 C:3 B:1 

注意:我是 Eclipse Collections 的提交者

【讨论】:

  • 看起来很有趣!问题是这些“A”、“B”等有数百个,因此手动计算它们中的每一个都不是一种选择。有没有办法恢复这些值并直接计算它们?
  • 您有几个选择。这实际上取决于您要如何操作数据。您可以在每个 Bag 上调用 toStringOfItemToCount()、forEachWithOccurrences() 或 topOccurrences()。我会给你一个例子。您还可以使用简单的 groupBy、、 创建 BagMultimap 结构
  • 不错!当我将数据存储到哈希中时,我发现了一个问题 :( 每次我发现同一个键的新出现并将其分隔时,它都会存储一个“,”。问题是记录本身使用“;”来该字段的多个值。我可能不得不退后一步,在将我的数组列表插入我的哈希之前。非常感谢你的回答!
【解决方案2】:

这是 Java 8 的“简单”解决方案:

import static java.util.stream.Collectors.*;

Map<String, Map<String, Long>> props =
  map.entrySet().stream().collect(toMap(Map.Entry::getKey,
    e -> e.getValue().stream().collect(groupingBy(String::toString, counting()))));

这将为您提供一个年份映射到计数键映射。

【讨论】:

  • 我马上试一试,结果告诉你
  • 几乎可以工作,它按年份为每个“术语”提供计数,但所有这些“术语”的值都是 1。我做了一个测试,在我的哈希中重复一个术语,结果如下1997 {Neurosciences; Physiology; Multidisciplinary Sciences=1, Multidisciplinary Sciences=1} 我虽然@Tassos Bassoukos 不知道为什么它没有正确计算第一个项目
  • 发现一个问题。出于某种原因,如果我的列表中有多个项目,则它的计数不正确,例如:&lt;1997&gt; &lt;banana, apples; tea, soup; banana&gt; 它认为整个项目都在“;”之间作为列表中的一项。虽然banana和apples在同一个列表中,但是1997应该被认为是两个词,再读banana的时候加1,但它是把列表中的整个位置当作一个项目,不管有多少词在里面。
  • 那你没有正确拆分数据。
【解决方案3】:

希望目前你有类似的东西:

Map<String,List<String>> map = new HashMap<>();

因此您可以遍历所有键并获取每个键的计数,如下所示:

for (List<String> values : map.values()){
    System.out.println(values.size());
}

如果您需要计算键中每种类型的计数,则必须使用 values.get() 检查类型并计算每种类型。

【讨论】:

  • 我有类似的东西,就像你发布的那样。嗯,有趣的是,我认为这会给出整个列表的大小。让我试试这个:-)
  • 如果这不起作用,您可以参考另一个类似的问题,其中答案涉及类型定义为枚举:stackoverflow.com/questions/31486532/…
  • 正如我所想,这会给我每个“键”的每个列表的大小,但不会告诉我每次出现我有多少项目。
  • 问题是对于我的示例中的每个“字母”,我需要知道它的重复。您提供的代码运行良好,但对于每个键的每个列表的大小。
猜你喜欢
  • 2011-04-07
  • 1970-01-01
  • 2013-11-03
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
  • 2020-10-21
  • 1970-01-01
  • 2023-01-29
相关资源
最近更新 更多