简体   繁体   中英

Character counter in Java

So far this is what I tried:

public class CharacterCounter {

public static void main(String[] args){

    String string = "sashimi";

    int count = 0;
    for(int i =0; i < string.length(); i++){
        if(string.charAt(i) == 'i'){
            count++;
            }
    }

    System.out.println("The number of letter i is " + count);

} 
}

Output:

 The number of letter i is 2

But what I wanna do is, the program should count the most occurred characters.

For example here the string is SASHIMI , the output should be:

 the number of letter S is 2
 the number of letter I is 2

I'm stuck with this problem. I need your help. Thanks.

This would be the fastest way:

final int[] counts = new int[1<<16];

for (char c : <your_string>)
  counts[c]++;

(i've just sketched out the part which iterates over all your chars, I believe that's the easy part, and not directly related to this question).

Benchmark results

I've pitted the HashMap approach against mine with three string lengths:

  1. 10
  2. 1,000
  3. 100,000

And these are the results:

Benchmark       Mode Thr    Cnt  Sec         Mean   Mean error    Units
testArray1      thrpt   1      5    5        6.870        0.083 ops/msec
testArray2      thrpt   1      5    5        6.720        0.374 ops/msec
testArray3      thrpt   1      5    5        3.770        0.019 ops/msec
testHashMap1    thrpt   1      5    5     1269.123      251.766 ops/msec
testHashMap2    thrpt   1      5    5       12.776        0.165 ops/msec
testHashMap3    thrpt   1      5    5        0.141        0.005 ops/msec

What do they mean? Yes, initializing a full 512K block of memory to zero is costly. But after that is paid, my array algorithm hardly even notices the thousands of characters whizzing by. The HashMap approach, on the other hand, is much faster for very short strings, but scales dramatically worse. I guess the crossover is at about 2k string length.

I suppose it is not disputed that such character-count statistics are usually run against massive text corpora, and not stuff like your name and surname.

Of course, the performance of the array approach can be improved substantially if you can assume that not the complete UTF-16 codepoint range will be used. For example, if you use an array that accomodates only the lowest 1024 codepoints, the performance rises to 470 ops/msec.

    char[] chars = string.toCharArray();
    HashMap<Character, Integer> countMap = new HashMap<Character, Integer>();
    for (char aChar : chars) {
        if (countMap.containsKey(aChar)) {
            countMap.put(aChar, countMap.get(aChar) + 1);
        } else {
            countMap.put(aChar,1);
        }
    }

    //determine max occurence
    int max = 0;
    for (Integer i: countMap.values()) {
        if (max < i) {
            max = i;
        }
    }

    //print all satisfiying max occurrence
    for (Map.Entry<Character, Integer> e: countMap.entrySet()) {
        if (e.getValue() == max) {
            System.out.println("The number of letter " + e.getKey() + "  is " + max);
        }
    }

I believe that using primitives would be faster than using HashMap . This works :

public static void main(String[] args)
{
    final String string = "sashimi";
    final int counters[] = new int[256]; // assuming you would use only ASCII chars
    for (final char c : string.toCharArray())
    {
        counters[c]++;
    }
    int maxCounter = 0;
    for (final int counter : counters)
    {
        if (maxCounter < counter)
        {
            maxCounter = counter;
        }
    }
    for (int i = 0; i < counters.length; i++)
    {
        if (counters[i] == maxCounter)
        {
            System.out.printf("%c has %d occurences.\n", i, counters[i]);
        }
    }
}

Output:

i has 2 occurences.
s has 2 occurences.

As mentioned in the comments, a HashMap seems ideal for this, although I won't give you the direct code, I'll give you a pseduo-code template.

for(each letter in a word)
{
    if(this letter (l) exists in your hash map)
    {
         hashmap.put(l, hashmap.get(l) ++);
    }
    else
    {
         hashmap.put(l, 1);
    }
}

This will give you a hashmap of all letters, mapped to the amount of times they appear in a word. Following your example:

S => 2
A => 1
H => 1
I => 2
M => 1

I suggest you create a TreeSet and then you can have a new class that will store the character and the number of ocurrences, then you can have that class have a compareTo that checks the occurrence and an equals that checks the char. Then whenever you insert them in the treeset they will always be in the order of whichever one appeared the most.

Please let me know if you need help with this or if you can figure it out with this information :)

EDIT: once you have filled the TreeSet with all of the letters, all you have to do is start getting them out 1 by 1 until the occcurence of the one that you took out is less than the one you took before (ie, if the top 3 letters appeared 3 times and the forth one 2, you only display the first 3).

您必须使用HashMap来保留重复时间最多的重复字符并进行打印。

What you need to do is to take the literal (string). And look over each char of it and put it to proper bucket. In other words you need to group them.

You could create a bucket for each letter of alphabet. Then you could place the char in proper bucket and at the end count the items in it to have the answer.

See Marko answer, that do this.

Another option is that you sort your literal AHIIMSS , then using simple loop you will be able to write the results.

The method you pick depends the result you need to get. If you need to find how many of each letter ware using in word then sort options is more tide, if you need to pick only the maximum letters then solution with buckets is more useful.

import java.util.*;

public class CharacterCounter {

public static void main(String[] args){

String string = "sashimi";
int count = 0;
ArrayList<Character> c = new ArrayList<Character>();
for(int i =0; i <string.length(); i++)
{
    count=0;
    if(c.contains(string.charAt(i)))
    {
        continue;
    }   
    c.add(string.charAt(i));        
    for(int j = 0;j<string.length();j++)
    {

        if(string.charAt(j) == string.charAt(i))
        {

            count++;

        }


    }
    System.out.println("The number of letter "+string.charAt(i)+" is " + count);
}

} }

    String str = "sashimi";
    Map<Character,Integer> countMap=new HashMap<Character,Integer>();
    Set<Character> maxcSet=new HashSet<Character>();
    Character maxC=null;
    Integer maxCount=null;
    for (int i = 0; i < str.length(); i++) {
        char c=str.charAt(i);
        Integer tempCount=countMap.get(c);

        if(tempCount==null){
            tempCount=0;
        }

        ++tempCount;

        if(i==0){
            maxCount=tempCount;
            maxC=c;
        }else if(tempCount!=null){
            if(maxCount<tempCount){
                maxC=c;
                maxCount=tempCount;
                maxcSet.clear();
                maxcSet.add(maxC);
            }else if(maxCount==tempCount){
                maxcSet.add(c);
            }
        }
        countMap.put(c, tempCount);
    }

    System.out.println("The number of letter i is " + maxcSet);
import java.util.Scanner;


public class CountingCharecter {
public static void main(String[] args) throws Exception {
    ///Reading Data String from keyboard
    int count=0;
    System.out.println("Enter Your String:");
    Scanner sc = new Scanner(System.in);
    String s1 = sc.nextLine();
    //// Reading `Character` Data from Keyboard
    System.out.println("Enter an character:");
    //Here we read the character from console type cast the character because the read() return type is int
    char ch =(char)System.in.read();
    for(int i=0;i<s1.length();i++){
           char c = s1.charAt(i);
           if(c==ch){
               count++;
           }//if


    }//for
    System.out.println("The Number of character which you want to search is having: "+count+" Times");
}
}//CharecterCount
/*

input:- Enter Your String: Manash Enter an character: a output:- 2

*/

 public static int numberOfOccurence(String yourString, char needle) {
      int nb = 0;
      for (int i=0; i < yourString.length(); i++)
    {
        if (yourString.charAt(i) == needle)
                   nb++;

    }
    return nb;
}

You can also use Pattern and Matcher :

   Pattern pattern = Pattern.compile("i");
   Matcher  matcher = pattern.matcher("saigigd");

   int count = 0;
   while (matcher.find())
   count++;
   System.out.println(count); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM