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).
Solution 1
How about this. It doesn't use regexp underneath so should be faster than some of the other solutions and won't use a loop.
int count = line.length() - line.replace(".", "").length();
Solution 2
My 'idiomatic one-liner' for this is:
int count = StringUtils.countMatches("a.b.c.d", ".");
Why write it yourself when it's already in commons lang?
Spring Framework's oneliner for this is:
int occurance = StringUtils.countOccurrencesOf("a.b.c.d", ".");
Solution 3
Summarize other answer and what I know all ways to do this using a one-liner:
String testString = "a.b.c.d";
1) Using Apache Commons
int apache = StringUtils.countMatches(testString, ".");
System.out.println("apache = " + apache);
2) Using Spring Framework's
int spring = org.springframework.util.StringUtils.countOccurrencesOf(testString, ".");
System.out.println("spring = " + spring);
3) Using replace
int replace = testString.length() - testString.replace(".", "").length();
System.out.println("replace = " + replace);
4) Using replaceAll (case 1)
int replaceAll = testString.replaceAll("[^.]", "").length();
System.out.println("replaceAll = " + replaceAll);
5) Using replaceAll (case 2)
int replaceAllCase2 = testString.length() - testString.replaceAll("\\.", "").length();
System.out.println("replaceAll (second case) = " + replaceAllCase2);
6) Using split
int split = testString.split("\\.",-1).length-1;
System.out.println("split = " + split);
7) Using Java8 (case 1)
long java8 = testString.chars().filter(ch -> ch =='.').count();
System.out.println("java8 = " + java8);
8) Using Java8 (case 2), may be better for unicode than case 1
long java8Case2 = testString.codePoints().filter(ch -> ch =='.').count();
System.out.println("java8 (second case) = " + java8Case2);
9) Using StringTokenizer
int stringTokenizer = new StringTokenizer(" " +testString + " ", ".").countTokens()-1;
System.out.println("stringTokenizer = " + stringTokenizer);
From comment: Be carefull for the StringTokenizer, for a.b.c.d it will work but for a...b.c....d or ...a.b.c.d or a....b......c.....d... or etc. it will not work. It just will count for . between characters just once
More info in github
Perfomance test (using JMH, mode = AverageTime, score 0.010 better then 0.351):
Benchmark Mode Cnt Score Error Units
1. countMatches avgt 5 0.010 ± 0.001 us/op
2. countOccurrencesOf avgt 5 0.010 ± 0.001 us/op
3. stringTokenizer avgt 5 0.028 ± 0.002 us/op
4. java8_1 avgt 5 0.077 ± 0.005 us/op
5. java8_2 avgt 5 0.078 ± 0.003 us/op
6. split avgt 5 0.137 ± 0.009 us/op
7. replaceAll_2 avgt 5 0.302 ± 0.047 us/op
8. replace avgt 5 0.303 ± 0.034 us/op
9. replaceAll_1 avgt 5 0.351 ± 0.045 us/op
Solution 4
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.
Solution 5
I had an idea similar to Mladen, but the opposite...
String s = "a.b.c.d";
int charCount = s.replaceAll("[^.]", "").length();
println(charCount);
Solution 6
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'.
Solution 7
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.
Solution 8
String s = "a.b.c.d";
long result = s.chars().filter(ch -> ch == '.').count();
Solution 9
A shorter example is
String text = "a.b.c.d";
int count = text.split("\\.",-1).length-1;
Solution 10
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
Solution 11
I don't like the idea of allocating a new string for this purpose. And as the string already has a char array in the back where it stores it's value, String.charAt() is practically free.
for(int i=0;i<s.length();num+=(s.charAt(i++)==delim?1:0))
does the trick, without additional allocations that need collection, in 1 line or less, with only J2SE.
Solution 12
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.
Solution 13
Not sure about the efficiency of this, but it's the shortest code I could write without bringing in 3rd party libs:
public static int numberOf(String target, String content)
{
return (content.split(target).length - 1);
}
Solution 14
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;
}
Solution 15
With java-8 you could also use streams to achieve this. Obviously there is an iteration behind the scenes, but you don't have to write it explicitly!
public static long countOccurences(String s, char c){
return s.chars().filter(ch -> ch == c).count();
}
countOccurences("a.b.c.d", '.'); //3
countOccurences("hello world", 'l'); //3
Solution 16
Also possible to use reduce in Java 8 to solve this problem:
int res = "abdsd3$asda$asasdd$sadas".chars().reduce(0, (a, c) -> a + (c == '$' ? 1 : 0));
System.out.println(res);
Output:
3
Solution 17
The simplest way to get the answer is as follow:
public static void main(String[] args) {
String string = "a.b.c.d";
String []splitArray = string.split("\\.",-1);
System.out.println("No of . chars is : " + (splitArray.length-1));
}
Solution 18
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
Solution 19
In case you're using Spring framework, you might also use "StringUtils" class. The method would be "countOccurrencesOf".
Solution 20
You can use the split() function in just one line code
int noOccurence=string.split("#",-1).length-1;
Solution 21
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");
Solution 22
public static int countOccurrences(String container, String content){
int lastIndex, currIndex = 0, occurrences = 0;
while(true) {
lastIndex = container.indexOf(content, currIndex);
if(lastIndex == -1) {
break;
}
currIndex = lastIndex + content.length();
occurrences++;
}
return occurrences;
}
Solution 23
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.
Solution 24
import java.util.Scanner;
class apples {
public static void main(String args[]) {
Scanner bucky = new Scanner(System.in);
String hello = bucky.nextLine();
int charCount = hello.length() - hello.replaceAll("e", "").length();
System.out.println(charCount);
}
}// COUNTS NUMBER OF "e" CHAR´s within any string input
Solution 25
Well, with a quite similar task I stumbled upon this Thread. I did not see any programming language restriction and since groovy runs on a java vm: Here is how I was able to solve my Problem using Groovy.
"a.b.c.".count(".")
done.
Solution 26
Using Eclipse Collections
int count = Strings.asChars("a.b.c.d").count(c -> c == '.');
If you have more than one character to count, you can use a CharBag as follows:
CharBag bag = Strings.asChars("a.b.c.d").toBag();
int count = bag.occurrencesOf('.');
Note: I am a committer for Eclipse Collections.
Solution 27
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
Solution 28
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);
}
Solution 29
Why not just split on the character and then get the length of the resulting array. array length will always be number of instances + 1. Right?
Solution 30
The following source code will give you no.of occurrences of a given string in a word entered by user :-
import java.util.Scanner;
public class CountingOccurences {
public static void main(String[] args) {
Scanner inp= new Scanner(System.in);
String str;
char ch;
int count=0;
System.out.println("Enter the string:");
str=inp.nextLine();
while(str.length()>0)
{
ch=str.charAt(0);
int i=0;
while(str.charAt(i)==ch)
{
count =count+i;
i++;
}
str.substring(count);
System.out.println(ch);
System.out.println(count);
}
}
}
