5

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.

15
  • When I run your program, I get the expected result. And the code looks good as well. Commented May 22, 2016 at 15:13
  • What is your expected output? Commented May 22, 2016 at 15:14
  • Something like this: L: 3 O: 2 H: 1 D: 1 E: 1 R: 1 W: 1 In nonalphabetical order Commented May 22, 2016 at 15:16
  • Why such output is expected? You count letters in alphabetical order, why do you expect output not to be? Commented May 22, 2016 at 15:20
  • I think u told actual output.. I mean what should be the output Commented May 22, 2016 at 15:20

3 Answers 3

3

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

Sign up to request clarification or add additional context in comments.

Comments

1

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

Comments

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

1 Comment

@Robert : Sorry for that. Formatted it. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.