У мене струна
a.b.c.d
Я хочу порахувати події "." ідіоматичним способом, переважно однолінійним.
(Раніше я висловлював це обмеження як "без циклу", на випадок, якщо вам цікаво, чому всі намагаються відповісти, не використовуючи цикл).
У мене струна
a.b.c.d
Я хочу порахувати події "." ідіоматичним способом, переважно однолінійним.
(Раніше я висловлював це обмеження як "без циклу", на випадок, якщо вам цікаво, чому всі намагаються відповісти, не використовуючи цикл).
Відповіді:
Мій "ідіоматичний однолінійний" для цього:
int count = StringUtils.countMatches("a.b.c.d", ".");
Навіщо писати його самостійно, коли це вже є у загальній публікації ?
Один ліній для цього Spring Framework є:
int occurance = StringUtils.countOccurrencesOf("a.b.c.d", ".");
int count = CharMatcher.is('.').countIn("a.b.c.d");
... На відповідь догбена в повторному запитанні.
Як щодо цього. Він не використовує regexp під ним, тому повинен бути швидшим, ніж деякі інші рішення, і не використовуватиме цикл.
int count = line.length() - line.replace(".", "").length();
Узагальнити іншу відповідь і те, що я знаю всі способи зробити це за допомогою однолінійки:
String testString = "a.b.c.d";
1) Використання Apache Commons
int apache = StringUtils.countMatches(testString, ".");
System.out.println("apache = " + apache);
2) Використання Spring Framework
int spring = org.springframework.util.StringUtils.countOccurrencesOf(testString, ".");
System.out.println("spring = " + spring);
3) Використання заміни
int replace = testString.length() - testString.replace(".", "").length();
System.out.println("replace = " + replace);
4) Використання substituAll (випадок 1)
int replaceAll = testString.replaceAll("[^.]", "").length();
System.out.println("replaceAll = " + replaceAll);
5) Використання substituAll (випадок 2)
int replaceAllCase2 = testString.length() - testString.replaceAll("\\.", "").length();
System.out.println("replaceAll (second case) = " + replaceAllCase2);
6) Використання спліт
int split = testString.split("\\.",-1).length-1;
System.out.println("split = " + split);
7) Використання Java8 (випадок 1)
long java8 = testString.chars().filter(ch -> ch =='.').count();
System.out.println("java8 = " + java8);
8) Використання Java8 (випадок 2) може бути кращим для unicode, ніж випадок 1
long java8Case2 = testString.codePoints().filter(ch -> ch =='.').count();
System.out.println("java8 (second case) = " + java8Case2);
9) Використання StringTokenizer
int stringTokenizer = new StringTokenizer(" " +testString + " ", ".").countTokens()-1;
System.out.println("stringTokenizer = " + stringTokenizer);
З коментаря : будьте обережні для StringTokenizer, для abcd він буде працювати, але для ... bc ... d або ... abcd або a .... b ...... c ..... d ... або т. д. це не спрацює. Це просто буде рахуватися. між персонажами лише один раз
Більше інформації в github
Тест на працездатність (використовуючи JMH , режим = AverageTime, бал 0.010
краще, ніж тоді 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
"1🚲2🚲3 has 2".codePoints().filter((c) -> c == "🚲".codePointAt(0)).count()
Рано чи пізно щось треба зациклювати. Написати (дуже простий) цикл вам набагато простіше, ніж використовувати щось подібне, split
яке набагато потужніше, ніж вам потрібно.
Обов`язково капсулюйте цикл окремим методом, наприклад
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;
}
Тоді вам не потрібен цикл у вашому головному коді - але цикл повинен бути десь там.
length()
виклику за межі циклу може зробити продуктивність гірше , як було згадано @ShuggyCoUk кілька зауважень вгору.
У мене була ідея, схожа на Младена, але навпаки ...
String s = "a.b.c.d";
int charCount = s.replaceAll("[^.]", "").length();
println(charCount);
replaceAll()
і length()
. виконуються десятки петель . Ну, якщо його не видно, його не існує; o)
String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();
ReplaceAll (".") Замінить усі символи.
Рішення PhiLho використовує ReplaceAll ("[^.]", ""), Якого не потрібно уникати, оскільки [.] Являє собою символ "крапка", а не "жоден символ".
Моє "ідіоматичне однолінійне" рішення:
int count = "a.b.c.d".length() - "a.b.c.d".replace(".", "").length();
Поняття не маю, чому приймається рішення, яке використовує StringUtils.
Коротший приклад - це
String text = "a.b.c.d";
int count = text.split("\\.",-1).length-1;
ось рішення без циклу:
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));
ну, є цикл, але він невидимий :-)
- Йонатан
Мені не подобається ідея виділяти для цього нову рядок. Оскільки рядок уже має масив char іззаду, де він зберігає його значення, String.charAt () практично безкоштовний.
for(int i=0;i<s.length();num+=(s.charAt(i++)==delim?1:0))
робить фокус без додаткових асигнувань, які потребують збору, в 1 рядок або менше, лише J2SE.
charAt
повторюється через 16 бітових кодових очок, а не символів! A char
на Java не є символом. Отже, ця відповідь означає, що не повинно бути символу Unicode з високим сурогатом, рівним кодовій точці delim
. Я не впевнений, чи правильно це для точки, але в цілому це може бути неправильно.
Гаразд, натхненний рішенням Йонатана, ось такий, який є суто рекурсивним - єдині використовувані методи бібліотеки є, length()
і charAt()
жоден з них не робить певного циклу:
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);
}
Чи вважатиметься рекурсія циклічною, залежно від того, яке саме визначення ви використовуєте, але воно, ймовірно, наближається.
Я не знаю, чи справді більшість JVM рецидивують хвостиком ... якщо ні, то, звичайно, ви не отримаєте однойменний стек переповнення відповідних довгих рядків.
Натхненний Джоном Скітом, версія без циклу, яка звичайно не підірве ваш стек. Також корисна відправна точка, якщо ви хочете використовувати рамку fork-join.
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);
}
}
(Відмова: Не перевірено, не складено, не є розумним.)
Мабуть, найкращий (однопоточний, без підтримки сурогатних пар) спосіб його написати:
public static int countOccurrences(String haystack, char needle) {
int count = 0;
for (char c : haystack.toCharArray()) {
if (c == needle) {
++count;
}
}
return count;
}
Не впевнений у ефективності цього, але це найкоротший код, який я міг би написати, не вводячи сторонні лібри:
public static int numberOf(String target, String content)
{
return (content.split(target).length - 1);
}
З java-8Ви також можете використовувати потоки для цього. Очевидно, є ітерація за лаштунками, але не потрібно писати це прямо!
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
.codePoints()
замість .chars()
цього підтримує будь-яке значення Unicode (включаючи ті, що вимагають сурогатних пар)
Для вирішення цієї проблеми також можливе використання скорочення в Java 8:
int res = "abdsd3$asda$asasdd$sadas".chars().reduce(0, (a, c) -> a + (c == '$' ? 1 : 0));
System.out.println(res);
Вихід:
3
Повний зразок:
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;
}
}
Виклик:
int occurrences = CharacterCounter.countOccurrences("l", "Hello World.");
System.out.println(occurrences); // 3
Найпростіший спосіб отримати відповідь:
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));
}
Якщо ви використовуєте Spring Framework, ви також можете використовувати клас "StringUtils". Метод буде "countOccurrencesOf".
Ви можете використовувати split()
функцію лише в одному кодовому рядку
int noOccurence=string.split("#",-1).length-1;
limit
встановлений на нулі в цьому перевантаженому виклику методу розділеного доступу. Приклад: "1##2#3#####".split("#")
отримає лише масив розміром 4 ( [0:"1";1:""; 2:"2"; 3:"3"]
) замість розміру 9 ( [0:"1"; 1:""; 2:"2"; 3:"3"; 4:""; 5:""; 6:""; 7:""; 8:""]
).
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;
}
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
Хоча методи можуть це приховати, неможливо порахувати без циклу (або рекурсії). Ви хочете використовувати знак char] з міркувань продуктивності.
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;
}
Використання substituAll (тобто RE) виглядає не найкращим чином.
Ну, з досить подібним завданням я натрапив на цю Нитку. Я не бачив жодних обмежень мови програмування, і оскільки groovy працює на java vm: Ось як я зміг вирішити свою проблему за допомогою Groovy.
"a.b.c.".count(".")
зроблено.
Набагато простішим рішенням було б просто розділити рядок на основі символу, з яким ви співпадаєте.
Наприклад,
int getOccurences(String characters, String string) {
String[] words = string.split(characters);
return words.length - 1;
}
У випадку:
getOccurences("o", "something about a quick brown fox");
Десь у коді щось має крутитися. Єдиний спосіб цього - повне розкручування циклу:
int numDots = 0;
if (s.charAt(0) == '.') {
numDots++;
}
if (s.charAt(1) == '.') {
numDots++;
}
if (s.charAt(2) == '.') {
numDots++;
}
... і т.д., але тоді ви робите цикл, вручну, в редакторі джерел - замість комп'ютера, який запустить його. Дивіться псевдокод:
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
Ось дещо інше рішення стилю рекурсії:
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);
}
Чому б просто не розділити на персонаж і потім отримати довжину отриманого масиву. Довжина масиву завжди буде числом екземплярів + 1. Так?
Наступний вихідний код дасть вам кількість випадків у заданому рядку у слові, введеному користувачем: -
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);
}
}
}