在Hash<String,List<String>>中,统计列表项值的出现次数

4
我有一个哈希结构 hash_feat <String, List<String>>,其中我的年份(Years),而列表中包含不同术语的列表。
我已经以一种方式拥有了我的哈希结构,使得特定的所有项目都在该键的同一列表中,如下所示: <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等,其他也是如此。 我试图想出这个方法,以便稍后在图表中显示每个项目的最高计数。可能这不是最聪明的方法,因此任何建议都会受到欢迎。思路是统计我的列表中每个项目的数量,以便可以在其他方法中操作/使用。
有没有什么聪明的方法来实现这个目标?

1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - user180100
3个回答

4

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”等等有一百多个,所以手动计数不是一个选项。 有没有办法直接恢复每个值并计算它们? - Terry Ruas
你有几个选项。这取决于你想如何操作数据。你可以在每个Bag上调用toStringOfItemToCount()、forEachWithOccurrences()或topOccurrences()。我会给你举一个例子。你也可以通过使用简单的groupBy来创建BagMultimap结构。 - Donald Raab
不错!我发现了一个问题,当我将数据存储到哈希表中时:(每次找到相同的键并分隔它时,它都会存储“,”。问题在于记录本身使用“;”来表示该字段的多个值。我可能需要退一步,在插入哈希表之前处理我的数组列表。非常感谢您的回答! - Terry Ruas

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()))));

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

我现在会尝试一下,并且会告诉您结果。 - Terry Ruas
几乎成功了,它按年份为每个“术语”提供计数,但所有值都为1。 我进行了一个测试,将一个术语重复放入我的哈希中,结果如下: 1997 {神经科学; 生理学; 多学科科学=1,多学科科学=1}我不知道为什么它没有正确计算前面的项,尽管@Tassos Bassoukos。 - Terry Ruas
发现了一个问题。 由于某种原因,如果我的列表中有多个项目,则无法正确计数,例如: <1997> <香蕉,苹果; 茶,汤; 香蕉> 它将“;”之间的整个项目视为列表中的一个项目。 尽管香蕉和苹果在同一个列表中,但它们应该被视为1997的两个单词,并在再次读取香蕉时添加+1,但它将列表中的整个位置视为一个单独的项目,无论其中有多少个单词。 - Terry Ruas
1
那么你没有正确地分割数据。 - Tassos Bassoukos

0

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

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

所以你可以通过迭代所有键并按如下方式获取每个键的计数:

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

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

我有和你发布的一模一样的东西。 嗯,有趣,我以为这会给出整个列表的大小。 让我试试 :-) - Terry Ruas
如果这个方法不起作用,您可以参考另一个类似的问题,其中答案涉及类型定义为枚举:http://stackoverflow.com/questions/31486532/how-to-count-key-values-in-a-hashmap - Aajan
正如我所想,这将为我提供每个“键”对应的每个列表的大小,但并不告诉我每个出现次数有多少项。 - Terry Ruas
问题在于对于我的示例中的每个“字母”,我都需要知道它的重复次数。 您提供的代码完美地运行了,但是对于每个键的列表大小而言存在问题。 - Terry Ruas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接