justin
justin

Reputation: 151

How to count and sort letters in a string

I want to sort the letters from user input and print out how many of each letter there is in the string from the user. This is what I have so far and i would like to know if this is the right way to do it. I am relatively new to java so please keep things s simple as possible. Ive made a few adjustments to my code upon the suggestions that I use loops instead of large amounts of if else constructs. This is what I have:

public class Assignment9
{
public static void main( String [] args )
{
    String user_string = Input.getString( "Please enter a string" );
    int length = user_string.length();
    int char_number = 1;
    int alphabet[] = new int[26];
    for( int repeats = 0 , repeats <= length , repeats++ )
    {
        char letter = user_string.charAt( char_number );
        char to_be_tested = Character.toLowerCase( letter );
        int subscript = 0;
        for(int letter_number = 97 , letter_number <= 122 , letter_number++ )
        {
            char tester = (char) letter_number;

            if( to_be_tested == tester )
            {
                alphabet[subscript]++;
                subscript++;
            }
        }
        char_number++;
    }
    display( alphabet );
}
public static void display( int alphabet[] )
{
    int letter = 65;
    for( int a = 0; a < alphabet.length; a++ )
    {
        char character = ( char )letter;
        System.out.println ( "letter " + character + " count is " + alphabet[a] );
        letter++;
    }
}
}

I'm getting these errors

Compilation errors:

test.java:9: error: ';' expected
            for( int repeats = 0 , repeats <= length , repeats++ )
                                          ^
test.java:9: error: illegal start of expression
            for( int repeats = 0 , repeats <= length , repeats++ )
                                           ^
test.java:9: error: ';' expected
            for( int repeats = 0 , repeats <= length , repeats++ )
                                             ^
test.java:9: error: illegal start of expression
            for( int repeats = 0 , repeats <= length , repeats++ )
                                                     ^
test.java:9: error: ')' expected
            for( int repeats = 0 , repeats <= length , repeats++ )
                                                      ^
test.java:9: error: illegal start of expression
            for( int repeats = 0 , repeats <= length , repeats++ )
                                                                 ^
test.java:14: error: ';' expected
                    for(int letter_number = 97 , letter_number <= 122 , letter_number++ )
                                                              ^
test.java:14: error: illegal start of expression
                    for(int letter_number = 97 , letter_number <= 122 , letter_number++ )
                                                               ^
test.java:14: error: ';' expected
                    for(int letter_number = 97 , letter_number <= 122 , letter_number++ )
                                                                 ^
test.java:14: error: illegal start of expression
                    for(int letter_number = 97 , letter_number <= 122 , letter_number++ )
                                                                      ^
test.java:14: error: ')' expected
                    for(int letter_number = 97 , letter_number <= 122 , letter_number++ )
                                                                       ^
test.java:14: error: illegal start of expression
                    for(int letter_number = 97 , letter_number <= 122 , letter_number++ )
                                                                                        ^
12 errors

Upvotes: 3

Views: 2184

Answers (5)

Daniel Cerecedo
Daniel Cerecedo

Reputation: 6207

Using Java 8 Streams

    String data = "some letters to count";

    Stream.of(data.split("(?!^)"))
          .collect(Collectors.groupingBy(Function.identity(), TreeMap::new, Collectors.counting()))
          .forEach((key, value)->System.out.println(key+": "+value));

And here is the explanation:

  1. First we split the data in one letter strings using a regular expression: data.split("(?!^)"); and we obtain an array of String's.

    0 = "s" 1 = "o" 2 = "m" 3 = "e" 4 = " " 5 = "l" 6 = "e" 7 = "t" 8 = "t" 9 = "e" 10 = "r" 11 = "s" 12 = " " 13 = "t" 14 = "o" 15 = " " 16 = "c" 17 = "o" 18 = "u" 19 = "n" 20 = "t"

  2. We create a Stream from the said array: Stream.of(data.split("(?!^)"))

  3. We do all the sorting and counting in this step using a groupingBy Collector and passing a TreeMap (a SortedMap implementation that will keep MapEntry's sorted by key): .collect(Collectors.groupingBy(Function.identity(), TreeMap::new, Collectors.counting())).

    The result of this step is a sorted TreeMap with distinct single character String's as keys and the count of this character as value.

    0 = {TreeMap$Entry@755} " " -> "3" 1 = {TreeMap$Entry@756} "c" -> "1" 2 = {TreeMap$Entry@757} "e" -> "3" 3 = {TreeMap$Entry@758} "l" -> "1" 4 = {TreeMap$Entry@759} "m" -> "1" 5 = {TreeMap$Entry@760} "n" -> "1" 6 = {TreeMap$Entry@761} "o" -> "3" 7 = {TreeMap$Entry@762} "r" -> "1" 8 = {TreeMap$Entry@763} "s" -> "2" 9 = {TreeMap$Entry@764} "t" -> "4" 10 = {TreeMap$Entry@765} "u" -> "1"

  4. Finally we print the result: .forEach((key, value)->System.out.println(key+": "+value));

Upvotes: 0

knightcube
knightcube

Reputation: 159

The thing is YOU are doing all of the work. What you need to do is make the COMPUTER work. All those printing statements take lots of copy pasting for no good reason. Hence using loops is a much more efficient way. And since you already know loops you could have come up with this solution-

import java.io.*;

public class experiments {
public static void main(String[] args) throws IOException {

    //Scanner sc=new Scanner(System.in);
    BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

    int i,j;
    char chr;
    int len,count=0;
    System.out.println("Enter text-->");
    String str=br.readLine();
    str=str.toUpperCase();
    len=str.length();
    for(i='A';i<='Z';i++)
    {
        for(j=0;j<len;j++)
        {
            chr=str.charAt(j);
            if(chr==i)count++;              
        }
        System.out.println((char)i+"-->"+count);
        count=0;
    }
  }
}

Upvotes: 2

Tim Biegeleisen
Tim Biegeleisen

Reputation: 520968

I would much rather use a map here to store the counts of each of the letters:

Map<Character, Integer> letterMap = new HashMap<>();
String userString = Input.getString( "Please enter a string" );

for (int i=0; i < userString.length(); ++i) {
    char letter = userString.charAt(i);
    Integer value = letterMap.get(letter);

    letterMap.put(letter, value == null ? 1 : value.intValue() + 1);
}

for (Map.Entry<Character, Integer> entry : letterMap.entrySet()) {
    System.out.println("Letter '" + entry.getKey() + "' appeared " + entry.getValue() + " times.");
}

As @Stephank pointed out, this solution will not print any summary stats for letters which do not appear at all in the input. If you want to print stats for all letters, even if they do not appear, you could seed the map with the following code:

for (char letter = 'a'; letter <= 'z'; ++letter) {
    letterMap.put(letter, 0);
}

Upvotes: 1

Slimu
Slimu

Reputation: 2371

Here is a simpler way to count letters, ignoring case:

final int[] chars = new int[26];
for (char c : value.toLowerCase().toCharArray()) {
  if ((c >= 'a') && (c<= 'z')) {
     chars[c - 'a']++;
  }
}

Demo: https://repl.it/CmYR/0

Upvotes: 2

bdvll
bdvll

Reputation: 86

A simpler approach would be to use the map data structure. It stores (key, value) pairs. In your case the key would be the letter, and the value would be an integer representing the count. So when you encounter say, an 'a' you do yourMap.get('a') and increment the value paired with that key.

Here you can read about maps in java: https://docs.oracle.com/javase/7/docs/api/java/util/Map.html

Upvotes: 1

Related Questions