I have to create a program that counts the letters in string and I have a little problem with that.
This is my code in main
:
Scanner sc = new Scanner(System.in);
String str;
int count;
System.out.println("Enter some text: ");
str = sc.nextLine();
char ch;
System.out.println("Letters: ");
for (ch = (char) 65; ch <= 90; ch++) {
count = 0;
for (int i = 0; i < str.length(); i++) {
if (ch == str.charAt(i) || (ch + 32) == str.charAt(i)) {
count++;
}
}
if (count > 0) {
System.out.println(ch + ": " + count);
}
}
Everything looks fine, but the output should not be in alphabetical order, rather ordered by the number of letters descending.
For example, if you input Hello World, the output should be something like this:
L: 3
O: 2
H: 1
D: 1
E: 1
R: 1
W: 1
The output would be sorted in descending order of letter frequency. That means the most frequent letter should appear first and the least last.
The order for letters that appears in equal proportions must be in alphabetical order.
The problem is that your outer loop browse the letters in alphabetical order, and that's where you display the count.
I would instead recommend browsing the input string with a single loop, updating the count of each letter in a Map<Character, Integer>
as I encounter them.
Then once the input String
has been consumed, I would sort the Map
by descending values, and print each key/value pair.
Map<Character, Integer> lettersCount = new HashMap<>();
for (int i=0; i <str.length(); i++) {
Character current = str.charAt(i);
if (Character.isLetter(current)) {
Integer previousCount = lettersCount.get(current);
if (previousCount != null) {
lettersCount.put(current, previousCount + 1);
} else {
lettersCount.put(current, 1);
}
}
}
List<Map.Entry<Character, Integer>> list = new LinkedList<Map.Entry<Character, Integer>>( lettersCount.entrySet() );
Collections.sort( list, new Comparator<Map.Entry<Character, Integer>>()
{
public int compare( Map.Entry<Character, Integer> o1, Map.Entry<Character, Integer> o2 )
{
return (o2.getValue()).compareTo( o1.getValue() );
}
} );
for (Map.Entry<Character, Integer> entry : list) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
You can try it out on ideone.
As you can see, sorting a Map
by values isn't trivial :-/
If you want to sort the results then you'll have to store the results & then iterate over them by their count descending to print in order
The best data structure to store them into would be a heap, keyed off of count. Java supplies such a data structure as java.util.PriorityQueue which can take a comparator function which first compares count & then character
https://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str;
int count;
System.out.println("Enter some text: ");
str = sc.nextLine();
char ch;
System.out.println("Letters: ");
LinkedHashMap<String, Integer> charCountMap = new LinkedHashMap<String, Integer>();
for (ch = (char) 65; ch <= 90; ch++) {
count = 0;
for (int i = 0; i < str.length(); i++) {
if (ch == str.charAt(i) || (ch + 32) == str.charAt(i)) {
count++;
}
}
if (count > 0) {
System.out.println(ch + ": " + count);
charCountMap.put(ch + "", count);
}
}
LinkedHashMap<String, Integer> sortedMapBasedOnValues = sortHashMapByValues(charCountMap);
for (Map.Entry<String, Integer> entry : sortedMapBasedOnValues.entrySet()) {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}
}
// Following method used from
// http://stackoverflow.com/questions/8119366/sorting-hashmap-by-values
public static LinkedHashMap<String, Integer> sortHashMapByValues(LinkedHashMap<String, Integer> passedMap) {
List<String> mapKeys = new ArrayList<>(passedMap.keySet());
List<Integer> mapValues = new ArrayList<>(passedMap.values());
Collections.sort(mapValues, Collections.reverseOrder());
Collections.sort(mapKeys);
LinkedHashMap<String, Integer> sortedMap = new LinkedHashMap<>();
Iterator<Integer> valueIt = mapValues.iterator();
while (valueIt.hasNext()) {
Integer val = valueIt.next();
Iterator<String> keyIt = mapKeys.iterator();
while (keyIt.hasNext()) {
String key = keyIt.next();
Integer comp1 = passedMap.get(key);
Integer comp2 = val;
if (comp1.equals(comp2)) {
keyIt.remove();
sortedMap.put(key, val);
break;
}
}
}
return sortedMap;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With