How do I count the number of occurrences of a char in a String?

Viewed 968901

I have the string

a.b.c.d

I want to count the occurrences of '.' in an idiomatic way, preferably a one-liner.

(Previously I had expressed this constraint as "without a loop", in case you're wondering why everyone's trying to answer without using a loop).

48 Answers

Sooner or later, something has to loop. It's far simpler for you to write the (very simple) loop than to use something like split which is much more powerful than you need.

By all means encapsulate the loop in a separate method, e.g.

public static int countOccurrences(String haystack, char needle)
{
    int count = 0;
    for (int i=0; i < haystack.length(); i++)
    {
        if (haystack.charAt(i) == needle)
        {
             count++;
        }
    }
    return count;
}

Then you don't need have the loop in your main code - but the loop has to be there somewhere.

I had an idea similar to Mladen, but the opposite...

String s = "a.b.c.d";
int charCount = s.replaceAll("[^.]", "").length();
println(charCount);
String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();

ReplaceAll(".") would replace all characters.

PhiLho's solution uses ReplaceAll("[^.]",""), which does not need to be escaped, since [.] represents the character 'dot', not 'any character'.

My 'idiomatic one-liner' solution:

int count = "a.b.c.d".length() - "a.b.c.d".replace(".", "").length();

Have no idea why a solution that uses StringUtils is accepted.

here is a solution without a loop:

public static int countOccurrences(String haystack, char needle, int i){
    return ((i=haystack.indexOf(needle, i)) == -1)?0:1+countOccurrences(haystack, needle, i+1);}


System.out.println("num of dots is "+countOccurrences("a.b.c.d",'.',0));

well, there is a loop, but it is invisible :-)

-- Yonatan

Okay, inspired by Yonatan's solution, here's one which is purely recursive - the only library methods used are length() and charAt(), neither of which do any looping:

public static int countOccurrences(String haystack, char needle)
{
    return countOccurrences(haystack, needle, 0);
}

private static int countOccurrences(String haystack, char needle, int index)
{
    if (index >= haystack.length())
    {
        return 0;
    }

    int contribution = haystack.charAt(index) == needle ? 1 : 0;
    return contribution + countOccurrences(haystack, needle, index+1);
}

Whether recursion counts as looping depends on which exact definition you use, but it's probably as close as you'll get.

I don't know whether most JVMs do tail-recursion these days... if not you'll get the eponymous stack overflow for suitably long strings, of course.

Inspired by Jon Skeet, a non-loop version that wont blow your stack. Also useful starting point if you want to use the fork-join framework.

public static int countOccurrences(CharSequeunce haystack, char needle) {
    return countOccurrences(haystack, needle, 0, haystack.length);
}

// Alternatively String.substring/subsequence use to be relatively efficient
//   on most Java library implementations, but isn't any more [2013].
private static int countOccurrences(
    CharSequence haystack, char needle, int start, int end
) {
    if (start == end) {
        return 0;
    } else if (start+1 == end) {
        return haystack.charAt(start) == needle ? 1 : 0;
    } else {
        int mid = (end+start)>>>1; // Watch for integer overflow...
        return
            countOccurrences(haystack, needle, start, mid) +
            countOccurrences(haystack, needle, mid, end);
    }
}

(Disclaimer: Not tested, not compiled, not sensible.)

Perhaps the best (single-threaded, no surrogate-pair support) way to write it:

public static int countOccurrences(String haystack, char needle) {
    int count = 0;
    for (char c : haystack.toCharArray()) {
        if (c == needle) {
           ++count;
        }
    }
    return count;
}

Complete sample:

public class CharacterCounter
{

  public static int countOccurrences(String find, String string)
  {
    int count = 0;
    int indexOf = 0;

    while (indexOf > -1)
    {
      indexOf = string.indexOf(find, indexOf + 1);
      if (indexOf > -1)
        count++;
    }

    return count;
  }
}

Call:

int occurrences = CharacterCounter.countOccurrences("l", "Hello World.");
System.out.println(occurrences); // 3

A much easier solution would be to just the split the string based on the character you're matching it with.

For instance,

int getOccurences(String characters, String string) { String[] words = string.split(characters); return words.length - 1; }

This will return 4 in the case of: getOccurences("o", "something about a quick brown fox");

While methods can hide it, there is no way to count without a loop (or recursion). You want to use a char[] for performance reasons though.

public static int count( final String s, final char c ) {
  final char[] chars = s.toCharArray();
  int count = 0;
  for(int i=0; i<chars.length; i++) {
    if (chars[i] == c) {
      count++;
    }
  }
  return count;
}

Using replaceAll (that is RE) does not sound like the best way to go.

Somewhere in the code, something has to loop. The only way around this is a complete unrolling of the loop:

int numDots = 0;
if (s.charAt(0) == '.') {
    numDots++;
}

if (s.charAt(1) == '.') {
    numDots++;
}


if (s.charAt(2) == '.') {
    numDots++;
}

...etc, but then you're the one doing the loop, manually, in the source editor - instead of the computer that will run it. See the pseudocode:

create a project
position = 0
while (not end of string) {
    write check for character at position "position" (see above)
}
write code to output variable "numDots"
compile program
hand in homework
do not think of the loop that your "if"s may have been optimized and compiled to

Here is a slightly different style recursion solution:

public static int countOccurrences(String haystack, char needle)
{
    return countOccurrences(haystack, needle, 0);
}

private static int countOccurrences(String haystack, char needle, int accumulator)
{
    if (haystack.length() == 0) return accumulator;
    return countOccurrences(haystack.substring(1), needle, haystack.charAt(0) == needle ? accumulator + 1 : accumulator);
}

This is what I use to count the occurrences of a string.

Hope someone finds it helpful.

    private long countOccurrences(String occurrences, char findChar){
        return  occurrences.chars().filter( x -> {
            return x == findChar;
        }).count();
    }

Using Java 8 and a HashMap without any library for counting all the different chars:

private static void countChars(String string) {
    HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
    string.chars().forEach(letter -> hm.put(letter, (hm.containsKey(letter) ? hm.get(letter) : 0) + 1));
    hm.forEach((c, i) -> System.out.println(((char)c.intValue()) + ":" + i));
}

use a lambda function which removes all characters to count
the count is the difference of the before-length and after-length

String s = "a.b.c.d";
int count = s.length() - deleteChars.apply( s, "." ).length();  // 3

find deleteChars here


if you have to count the occurrences of more than one character it can be done in one swoop:
eg. for b c and .:

int count = s.length() - deleteChars.apply( s, "bc." ).length();  // 5

a lambda one-liner
w/o the need of an external library.
Creates a map with the count of each character:

Map<Character,Long> counts = "a.b.c.d".codePoints().boxed().collect(
    groupingBy( t -> (char)(int)t, counting() ) );

gets: {a=1, b=1, c=1, d=1, .=3}
the count of a certain character eg. '.' is given over:
counts.get( '.' )

(I also write a lambda solution out of morbid curiosity to find out how slow my solution is, preferably from the man with the 10-line solution.)

Here is most simple and easy to understand without using arrays, just by using Hashmap. Also it will calculate whitespaces, number of capital chars and small chars, special characters etc.

import java.util.HashMap;
  //The code by muralidharan  
    public class FindChars {
        
        public static void main(String[] args) {
            
            findchars("rererereerererererererere");
        }
        
        public static void findchars(String s){
            
            HashMap<Character,Integer> k=new HashMap<Character,Integer>();
            for(int i=0;i<s.length();i++){
                if(k.containsKey(s.charAt(i))){
                Integer v =k.get(s.charAt(i));
                k.put(s.charAt(i), v+1);
                }else{
                    k.put(s.charAt(i), 1);
                }
                
            }
            System.out.println(k);
            
        }
    
    }

O/P: {r=12, e=13}

second input:

findchars("The world is beautiful and $#$%%%%%%@@@@ is worst");

O/P: { =7, @=4, a=2, b=1, #=1, d=2, $=2, e=2, %=6, f=1, h=1, i=3, l=2, n=1, o=2, r=2, s=3, T=1, t=2, u=2, w=2}

 public static String encodeMap(String plainText){
        
        Map<Character,Integer> mapResult=new LinkedHashMap<Character,Integer>();
        String result = "";
        for(int i=0;i<plainText.length();i++){
            if(mapResult.containsKey(plainText.charAt(i))){
            Integer v =mapResult.get(plainText.charAt(i));
            mapResult.put(plainText.charAt(i), v+1);
            }else{
                mapResult.put(plainText.charAt(i), 1);
            }
        }
        
        for(Map.Entry<Character, Integer> t : mapResult.entrySet()) {
            result += String.valueOf(t.getKey())+t.getValue();
        }
        
        return result;
        
    }

 public static void main(String args[]) {
        String  plainText = "aaavvfff";
        System.out.println(encodeMap(plainText)); //a3v2f3  
    }
public static void getCharacter(String str){

        int count[]= new int[256];

        for(int i=0;i<str.length(); i++){


            count[str.charAt(i)]++;

        }
        System.out.println("The ascii values are:"+ Arrays.toString(count));

        //Now display wht character is repeated how many times

        for (int i = 0; i < count.length; i++) {
            if (count[i] > 0)
               System.out.println("Number of " + (char) i + ": " + count[i]);
        }


    }
}
Related