Простой способ подсчета появления символов в строке
Есть ли простой способ (вместо обхода вручную всей строки или цикла для indexOf), чтобы узнать, сколько раз символ появляется в строке?
Скажем, у нас есть "abdsd3$asda$asasdd$sadas", и мы хотим, чтобы $ появлялось 3 раза.
15 ответов
String s = "...";
int counter = 0;
for( int i=0; i<s.length(); i++ ) {
if( s.charAt(i) == '$' ) {
counter++;
}
}
Это определенно самый быстрый способ. Регулярные выражения здесь намного медленнее и их сложнее понять.
Функциональный стиль (Java 8, просто для удовольствия):
str.chars().filter(num -> num == '$').count()
Не оптимальный, но простой способ подсчета событий:
String s = "...";
int counter = s.split("\\$", -1).length - 1;
Замечания:
- Знак доллара является специальным символом регулярного выражения, поэтому его следует использовать с обратной косой чертой.
- Обратная косая черта - это специальный символ для escape-символов, таких как символы новой строки, поэтому ее следует экранировать обратной косой чертой.
- Второй аргумент split предотвращает удаление пустых завершающих строк.
Вы можете использовать Apache Commons' StringUtils.countMatches(String string, String subStringToCount)
,
Так как вы сканируете всю строку в любом случае, вы можете создать полное число символов и выполнить любое количество поисков, все за ту же самую большую стоимость - (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
Счетчик частот символов является обычной задачей для некоторых приложений (например, для обучения), но недостаточно общей, чтобы гарантировать включение в основные API Java. Таким образом, вам, вероятно, нужно написать свою собственную функцию.
Я полагаю, что "один вкладыш", который вы ожидали получить, таков:
"abdsd3$asda$asasdd$sadas".replaceAll( "[^$]*($)?", "$1" ).length();
Помните, что требования:
(вместо обхода вручную всей строки или цикла для indexOf)
и позвольте мне добавить: что в основе этого вопроса звучит так, будто "любая петля" не нужна, и нет требования к скорости. Я считаю, что подтекст этого вопроса является фактором крутости.
Вы также можете использовать для каждого цикла. Я думаю, что это проще для чтения.
int occurrences = 0;
for(char c : yourString.toCharArray()){
if(c == '$'){
occurrences++;
}
}
Что-то более функциональное, без 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);
}
Это не хвост рекурсивный, ради ясности.
Для этого есть множество различных утилит, например, Apache Commons Lang String Utils
но, в конце концов, он должен перебрать строку, чтобы подсчитать вхождения так или иначе.
Обратите внимание также, что countMatches
Метод выше имеет следующую подпись, поэтому будет работать и для подстрок.
public static int countMatches(String str, String sub)
Источник для этого ( отсюда):
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;
}
Мне было любопытно, перебирали ли они строку или использовали Regex.
Обход строки, вероятно, наиболее эффективен, хотя использование Regex для этого может привести к более чистому виду кода (хотя вы всегда можете скрыть свой код перемещения в функции).
Это простой код, но, конечно, немного медленнее.
String s = ...;
int countDollar = s.length()-s.replaceAll("\\$","").length();
int counta = s.length()-s.replaceAll("a","").length();
Еще лучший ответ здесь, в двойном вопросе
Вы можете посмотреть на сортировку строки - обработать ее как массив символов - и затем выполнить модифицированный двоичный поиск, который считает вхождения? Но я согласен с @tofutim, что обход его наиболее эффективен - O(N) против O(N * logN) + O(logN)
Есть еще один способ подсчета количества символов в каждой строке. Предполагая, что у нас есть строка какString str = "abfdvdvdfv"
Затем мы можем посчитать, сколько раз каждый символ появляется, пройдя только один раз как
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);
}
}
Затем мы можем проверить вывод, пройдя по карте как
for (Map.Entry<String, Integer> entry:map.entrySet())
{
System.out.println(entry.getKey()+" count is : "+entry.getValue())
}
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;
}
}