1

I wrote code that counts frequency of every character in a given string and displays it:

Map<Character, Integer> occurrences = new HashMap<>();
char[] chars = str2.toCharArray();
for (char character : chars) {
    Integer integer = occurrences.get(character);
    occurrences.put(character, integer);
    if (integer == null) {
        occurrences.put(character, 1);
    } else {
        occurrences.put(character, integer + 1);
    }
}
System.out.println(occurrences);

Now I want to modify my code, so it shows the characters ordered by their frequency. Starting with the character, that is most frequently repeated, then second most frequently, then third and so on.

For example the string Java should be displayed as character-frequency in following order: a=2, j=1, v=1.

hc_dev
  • 8,389
  • 1
  • 26
  • 38

4 Answers4

2

Consider using a TreeMap ( https://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html )

TreeMap is a map implementation that keeps its entries sorted according to the natural ordering of its keys.

You can refer to the below code for reference.

import java.util.Map;
import java.util.TreeMap; 

class Test { 
    static void characterCount(String inputString) 
    { 
        TreeMap<Character, Integer> charCountMap = new TreeMap<Character, Integer>(); 
        char[] strArray = inputString.toCharArray(); 
        for (char c : strArray) { 
            if (charCountMap.containsKey(c)) { 
                charCountMap.put(c, charCountMap.get(c) + 1); 
            } 
            else { 
                charCountMap.put(c, 1); 
            } 
        } 
        for (Map.Entry entry : charCountMap.entrySet()) { 
            System.out.println(entry.getKey() + "=" + entry.getValue()); 
        } 
    } 

    public static void main(String[] args) 
    { 
        String str = "welcometostackoverflow"; 
        characterCount(str); 
    } 
} 

Output :

a=1
c=2
e=3
f=1
k=1
l=2
m=1
o=4
r=1
s=1
t=2
v=1
w=2
Amit kumar
  • 2,169
  • 10
  • 25
  • 36
2

Try it like this.

String str = "To be or not to be, that is the question";
  • stream the characters and group based on character and count.
  • then restream the entry set to sort on the value
  • specifying a LinkedHashMap to preserve the sorted order.

The entries are sorted by value (count) first. If the counts are equals them the sort is by key.

Map<Character, Long> map = str.chars()
        .mapToObj(c -> Character.valueOf((char) c))
        .collect(Collectors
                .groupingBy(c -> c, Collectors.counting()))
        .entrySet().stream()
        .sorted(Entry.<Character, Long>comparingByValue()
                .reversed().thenComparing(Entry.comparingByKey()))
        .collect(Collectors.toMap(Entry::getKey,
                Entry::getValue, (a, b) -> a,
                LinkedHashMap::new));

map.entrySet().forEach(System.out::println);

Prints

 =9
t=6
o=5
e=4
b=2
h=2
i=2
n=2
s=2
,=1
T=1
a=1
q=1
r=1
u=1
WJS
  • 36,363
  • 4
  • 24
  • 39
1

If you use Java's TreeMap implementation of the Map it will keep your values sorted by key.

There is also a constructor where you can pass a custom implementation of Comparator if you need your way of sorting.

hc_dev
  • 8,389
  • 1
  • 26
  • 38
Tala
  • 8,888
  • 5
  • 34
  • 38
  • Thank you. But output is sorted in alphabetical order. I want to sort by number of occurrences. So 0=4, then e =3 and so on – Bakyt Dzhumabaev Jan 11 '21 at 04:45
  • @BakytDjumabaev TreeMap only sorts on the key. So you would have to put the count as the key and the letter as the value. That is why I did it the way I did it in my answer. To address your specific requirement. – WJS Jan 11 '21 at 14:36
  • Typo in "keep your _day_ sorted"? It's about sorting characters and their frequencies (at _day_ and at night ️). – hc_dev Mar 08 '21 at 23:22
  • Although your answer proposed an implementation, a code example like [Amit's](https://stackoverflow.com/a/65661289/5730279) would be practical ️ – hc_dev Mar 08 '21 at 23:28
0

You can collect two maps: the first map summing up the quantities, then sort it and collect the second sorted map. In this case, if the quantities are equal, then the encounter order is used:

String str = "JavaProgrammingLanguage";

Map<Character, Integer> occurrences = str.codePoints()
        // Stream<Character>
        .mapToObj(ch -> (char) ch)
        // collect to a map in insertion
        // order, summing up the quantities
        .collect(Collectors.toMap(
                // key - lowercase character
                Character::toLowerCase,
                // value - quantity '1'
                ch -> 1,
                // summing quantities
                Integer::sum,
                // insertion order
                LinkedHashMap::new))
        // Stream<Map.Entry<Character,Integer>>
        .entrySet().stream()
        // sort by quantity in reverse order
        .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
        // collect into a sorted map
        .collect(LinkedHashMap::new,
                (map, entry) -> map.put(entry.getKey(), entry.getValue()),
                HashMap::putAll);

// output
System.out.println(occurrences);
// {a=5, g=4, r=2, m=2, n=2, j=1, v=1, p=1, o=1, i=1, l=1, u=1, e=1}

See also: The intersection of all combinations of n sets