2

I am looking at a redundant list of Strings, e.g.

{ "One", "One", "One", "Two", "Three", "Three" }

What is the best way to count the occurrences, then create a non-redundant list of the strings, sorted by the number of occurrences?

The result I want is a List like this:

{ "One", "Three", "Two" }
Jonas Eicher
  • 1,413
  • 12
  • 18
  • You can use a modified `Set` which will automatically keep only one instance, and you can keep a count in another variable. – Ozair Kafray Jul 16 '12 at 13:04
  • Use a treemap instead of a hasamap – assylias Jul 16 '12 at 13:04
  • Try using TreeMap with a comparator http://docs.oracle.com/javase/1.5.0/docs/api/java/util/TreeMap.html#TreeMap%28java.util.Comparator%29 – Santosh Gokak Jul 16 '12 at 13:04
  • you could just split on space to get words and then use a hashset to delete duplicates [like so](http://stackoverflow.com/questions/10366856/delete-duplicate-strings-in-string-array) ? sorry if i am missing something – aishwarya Jul 16 '12 at 13:06
  • @aishwarya You are missing the *counting occurrences* bit. – Marko Topolnik Jul 16 '12 at 13:07

3 Answers3

6

You can use the trick in the most voted answer of this question about how to sort the map by its values.

Here is an example implementation (I have added generics to the comparator):

  • you add the strings / occurences to a hashmap
  • put everything in a TreeMap with a custom comparator that sorts on the values
  • put the keys back in a list
public static void main(String[] args) {
    String[] strings = {"One", "One", "One", "Two", "Three", "Three"};

    //Count occurences
    Map<String, Integer> map = new HashMap<String, Integer>();

    for (String s : strings) {
        if (map.containsKey(s)) {
            map.put(s, map.get(s) + 1);
        } else {
            map.put(s, 1);
        }
    }

    ValueComparator<String, Integer> comparator = new ValueComparator<String, Integer> (map);
    Map<String, Integer> sortedMap = new TreeMap<String, Integer> (comparator);
    sortedMap.putAll(map);

    List<String> sortedList = new ArrayList<String> (sortedMap.keySet());

    System.out.println(sortedMap);
    System.out.println(sortedList);

}

static class ValueComparator<K, V extends Comparable<V>> implements Comparator<K> {

    Map<K, V> map;

    public ValueComparator(Map<K, V> base) {
        this.map = base;
    }

    @Override
    public int compare(K o1, K o2) {
         return map.get(o2).compareTo(map.get(o1));
    }
}
Community
  • 1
  • 1
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 1
    The trick under your link is very fragile as it assumes the **value under a key will never change**. It is of key importance to follow that recipe in detail: use one map while building data (can be a hashmap), then **pour everything over** into the treemap with the custom comparator. – Marko Topolnik Jul 16 '12 at 13:12
  • @MarkoTopolnik You are right - was not as simple as I thought. – assylias Jul 16 '12 at 13:45
1

It can be done quickly in Java 8.

Map<String, Long> sortedByCountSet =  Stream.of("One", "One", "One", "Two", "Three", "Three")
            .collect(Collectors.groupingBy(str->str,TreeMap::new,Collectors.counting()));

System.out.println(sortedByCountSet);

Output here :-

{One=3, Three=2, Two=1}

OR

Map<String, Long> sortedByCountSet = Stream.of("One", "One", "One", "Two", "Three", "Three","Five","Five")
            .collect(Collectors.groupingBy(str->str, Collectors.counting()))
            .entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2) -> e1,LinkedHashMap::new));

Output:-

{Two=1, Five=2, Three=2, One=3}

Ajay Kumar
  • 4,864
  • 1
  • 41
  • 44
0

You could create a Map, go through your list, everytime you come across a new occurance put it into the list and set the integer value to 1, everytime you come across a duplicate just increase the value by one for that particular key.

Then go through and create your sorted list from the counts in the hashmap.

Or as others have suggested using a TreeMap will allow you to sort rather than creatign sepearet list.

Jon Taylor
  • 7,865
  • 5
  • 30
  • 55