Простой способ подсчета появления символов в строке

Есть ли простой способ (вместо обхода вручную всей строки или цикла для 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;
            }

        }
Другие вопросы по тегам