[java] Simple way to count character occurrences in a string

Is there a simple way (instead of traversing manually all the string, or loop for indexOf) in order to find how many times, a character appears in a string?

Say we have "abdsd3$asda$asasdd$sadas" and we want that $ appears 3 times.

This question is related to java string

The answer is


You can look at sorting the string -- treat it as a char array -- and then do a modified binary search which counts occurrences? But I agree with @tofutim that traversing it is the most efficient -- O(N) versus O(N * logN) + O(logN)


There is another way to count the number of characters in each string. Assuming we have a String as String str = "abfdvdvdfv"

We can then count the number of times each character appears by traversing only once as

for (int i = 0; i < str.length(); i++) 
{
    if(null==map.get(str.charAt(i)+""))
    {
        map.put(str.charAt(i)+"", new Integer(1));
    }
    else
    {
       Integer count = map.get(str.charAt(i)+"");
       map.put(str.charAt(i)+"", count+1);
    }
}

We can then check the output by traversing the Map as

for (Map.Entry<String, Integer> entry:map.entrySet()) 
{
    System.out.println(entry.getKey()+" count is : "+entry.getValue())

}

Functional style (Java 8, just for fun):

str.chars().filter(num -> num == '$').count()

You can use Apache Commons' StringUtils.countMatches(String string, String subStringToCount).


 public static int countChars(String input,char find){      
            if(input.indexOf(find) != -1){          
            return  countChars(input.substring(0, input.indexOf(find)), find)+ 
                countChars(input.substring(input.indexOf(find)+1),find) + 1;
            }
            else {
                return 0;
            }

        }

A character frequency count is a common task for some applications (such as education) but not general enough to warrant inclusion with the core Java APIs. As such, you'll probably need to write your own function.


I believe the "one liner" that you expected to get is this:

"abdsd3$asda$asasdd$sadas".replaceAll( "[^$]*($)?", "$1" ).length();

Remember that the requirements are:

(instead of traversing manually all the string, or loop for indexOf)

and let me add: that at the heart of this question it sounds like "any loop" is not wanted and there is no requirement for speed. I believe the subtext of this question is coolness factor.


you can also use a for each loop. I think it is simpler to read.

int occurrences = 0;
for(char c : yourString.toCharArray()){
   if(c == '$'){
      occurrences++;
   }
}

Not optimal, but simple way to count occurrences:

String s = "...";
int counter = s.split("\\$", -1).length - 1;

Note:

  • Dollar sign is a special Regular Expression symbol, so it must be escaped with a backslash.
  • A backslash is a special symbol for escape characters such as newlines, so it must be escaped with a backslash.
  • The second argument of split prevents empty trailing strings from being removed.

Well there are a bunch of different utilities for this, e.g. Apache Commons Lang String Utils

but in the end, it has to loop over the string to count the occurrences one way or another.

Note also that the countMatches method above has the following signature so will work for substrings as well.

public static int countMatches(String str, String sub)

The source for this is (from here):

public static int countMatches(String str, String sub) {
    if (isEmpty(str) || isEmpty(sub)) {
        return 0;
    }
    int count = 0;
    int idx = 0;
    while ((idx = str.indexOf(sub, idx)) != -1) {
        count++;
        idx += sub.length();
    }
    return count;
}

I was curious if they were iterating over the string or using Regex.


Traversing the string is probably the most efficient, though using Regex to do this might yield cleaner looking code (though you can always hide your traverse code in a function).


Something a bit more functional, without Regex:

public static int count(String s, char c) {
    return s.length()==0 ? 0 : (s.charAt(0)==c ? 1 : 0) + count(s.substring(1),c);
}

It's no tail recursive, for the sake of clarity.


This is simple code, but of course a little bit slower.

String s = ...;
int countDollar = s.length()-s.replaceAll("\\$","").length();
int counta = s.length()-s.replaceAll("a","").length();

An even better answer is here in a duplicate question


Since you're scanning the whole string anyway you can build a full character count and do any number of lookups, all for the same big-Oh cost (n):

public static Map<Character,Integer> getCharFreq(String s) {
  Map<Character,Integer> charFreq = new HashMap<Character,Integer>();
  if (s != null) {
    for (Character c : s.toCharArray()) {
      Integer count = charFreq.get(c);
      int newCount = (count==null ? 1 : count+1);
      charFreq.put(c, newCount);
    }
  }
  return charFreq;
}

// ...
String s = "abdsd3$asda$asasdd$sadas";
Map counts = getCharFreq(s);
counts.get('$'); // => 3
counts.get('a'); // => 7
counts.get('s'); // => 6