Terry Ruas
Terry Ruas

Reputation: 99

Counting occurrences of values of items inside a List within a Hash<String,List<String>>

I have a hash structure hash_feat <String, List<String>> where my keys are Years and the values list inside has a list of different terms.

I already have my hash has in a way that all items from a specific key are in the same list for that key, like:

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

I would like to have for each item a counting. For 1997 A:4, B:2, C:3, E:1 so on and so forth for the other keys.

I am trying to come up with this to use this "counting" to later display in a figure where I can visualize the highest counts for each item in a graph. Probably this is not the smartest way, so any advice here would be welcome as well.The idea is to have the quantity of each item in my list so I can manipulate/use in other methods.

Anyone have a good advice to do this in a smart way?

Upvotes: 4

Views: 424

Answers (3)

Donald Raab
Donald Raab

Reputation: 6686

There is a data structure in Eclipse Collections called BagMultimap that would would work well with your use case. Here is how to leverage MutableBagMultimap with your example data.

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

You can output the multimap simply using forEachKeyMultivalues and toStringOfItemToCount.

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

This code displays the following:

<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}

Or you can write the following using forEachWithOccurrences in order to control the output.

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

This code displays the following:

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  

Lastly, you can use topOccurrences if you'd like the output ordered from greatest occurrences to least.

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

This code displays the following:

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 

Note: I am a committer for Eclipse Collections

Upvotes: 4

Tassos Bassoukos
Tassos Bassoukos

Reputation: 16142

Here's a "simple" solution for 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()))));

This will give you a Map of years to a Map of keys to counts.

Upvotes: 2

Aajan
Aajan

Reputation: 937

Hope currently you have something like :

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

So you can iterate very through all the keys and get count for each key as below:

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

If you need the count of each type within key then you have to check type using values.get() and count each type.

Upvotes: 0

Related Questions