Zählen Sie die Anzahl jedes Zeichens in einem String

184451
statius

Ich weiß, dass es einen einfacheren Weg gibt, dies zu tun, aber ich kann gerade nicht wirklich daran denken. Kannst du mir bitte helfen?

String sample = "hello world";
char arraysample[] = sample.toCharArray();
int length = sample.length();

//count the number of each letter in the string
int acount = 0;
int bcount = 0;
int ccount = 0;
int dcount = 0;
int ecount = 0;
int fcount = 0;
int gcount = 0;
int hcount = 0;
int icount = 0;
int jcount = 0;
int kcount = 0;
int lcount = 0;
int mcount = 0;
int ncount = 0;
int ocount = 0;
int pcount = 0;
int qcount = 0;
int rcount = 0;
int scount = 0;
int tcount = 0;
int ucount = 0;
int vcount = 0;
int wcount = 0;
int xcount = 0;
int ycount = 0;
int zcount = 0; 

for(int i = 0; i < length; i++)
{
    char c = arraysample[i];
    switch (c) 
    {
        case 'a': 
            acount++;
            break;
        case 'b': 
            bcount++;
            break;
        case 'c': 
            ccount++;
            break;
        case 'd': 
            dcount++;
            break;
        case 'e':
            ecount++;
            break;
        case 'f':
            fcount++;
            break;
        case 'g':
            gcount++;
            break;
        case 'h':
            hcount++;
            break;
        case 'i':
            icount++;
            break;
        case 'j':
            jcount++;
            break;
        case 'k':
            kcount++;
            break;
        case 'l':
            lcount++;
            break;
        case 'm':
            mcount++;
            break;
        case 'n':
            ncount++;
            break;
        case 'o':
            ocount++;
            break;
        case 'p':
            pcount++;
            break;
        case 'q':
            qcount++;
            break;
        case 'r':
            rcount++;
            break;
        case 's':
            scount++;
            break;
        case 't':
            tcount++;
            break;
        case 'u':
            ucount++;
            break;
        case 'v':
            vcount++;
            break;
        case 'w':
            wcount++;
            break;
        case 'x':
            xcount++;
            break;
        case 'y':
            ycount++;
            break;
        case 'z':
            zcount++;
            break;
        }
}
System.out.println ("There are " +hcount+" h's in here ");
System.out.println ("There are " +ocount+" o's in here ");
Antworten
16

5 Antworten auf die Frage

32
Marco Acierno

Oh woah! xD It's just.. woah! What patience you have to write all those variables.

Well, it's Java so you can use a HashMap.

Write something like this:

String str = "Hello World";
int len = str.length();
Map<Character, Integer> numChars = new HashMap<Character, Integer>(Math.min(len, 26));

for (int i = 0; i < len; ++i)
{
    char charAt = str.charAt(i);

    if (!numChars.containsKey(charAt))
    {
        numChars.put(charAt, 1);
    }
    else
    {
        numChars.put(charAt, numChars.get(charAt) + 1);
    }
}

System.out.println(numChars);
  1. We do a for loop over all the string's characters and save the current char in the charAt variable
  2. We check if our HashMap already has a charAt key inside it
    • If it's true we will just get the current value and add one.. this means the string has already been found to have this char.
    • If it's false (i.e. we never found a char like this in the string), we add a key with value 1 because we found a new char
  3. Stop! Our HashMap will contain all chars (keys) found and how many times it's repeated (values)!
Als zusätzlicher Bonus unterstützt dies mehr als nur Kleinbuchstaben. unholysampler vor 6 Jahren 2
Sie können eine TreeMap anstelle einer HashMap in Betracht ziehen, sodass die Daten beim Drucken von der Sammlung selbst sortiert werden (wenn Sie sie alle drucken möchten). Wenn Sie bei einer HashMap bleiben, sollten Sie das Argument für die Initalfähigkeit des Konstruktors in Betracht ziehen, da Sie in dieser Situation nicht mehr als 26 Buchstaben erhalten. Best Practices und all das. vor 6 Jahren 6
@MichaelT TreeMap großartig! Ich würde das initialSize trotzdem auf str.length () setzen, da es sein könnte, dass jedes Zeichen nie wiederholt wird. Marco Acierno vor 6 Jahren 0
Dann wäre es min (str.len (), 26) `, denn wenn es länger als 26 Zeichen ist, werden * doppelte Zeichen vorhanden sein ... obwohl wir beide die Art von Leerzeichen ignorieren. Es ist jedoch nur ein Hinweis auf das System und es wird wachsen, wenn es nötig ist. Der Standardwert, mit dem begonnen wird, ist 16 (und wächst dann auf 32 und dann auf 64). Ich würde immer noch eine der Implementierungen [navigablemap] (http://docs.oracle.com/javase/7/docs/api/java/util/NavigableMap.html) für seine sortierte Natur verwenden. Ich mag die Überspringliste. vor 6 Jahren 1
Yup, min (str. length (), 26). Es ist nur um die "Wachstumskosten" zu vermeiden, wenn sie nicht benötigt werden Marco Acierno vor 6 Jahren 0
+1 speziell für "_woah_" und "_Stop! _" Sᴀᴍ Onᴇᴌᴀ vor einem Jahr 0
19
Simon Forsberg

A possibly faster, and at least more compact version than using a HashMap is to use a good old integer array. A char can actually be typecasted to an int, which gives it's ASCII code value.

String str = "Hello World";
int[] counts = new int[(int) Character.MAX_VALUE];
// If you are certain you will only have ASCII characters, I would use `new int[256]` instead

for (int i = 0; i < str.length(); i++) {
    char charAt = str.charAt(i);
    counts[(int) charAt]++;
}

System.out.println(Arrays.toString(counts));

As the above output is a bit big, by looping through the integer array you can output just the characters which actually occur:

for (int i = 0; i < counts.length; i++) {
    if (counts[i] > 0)
        System.out.println("Number of " + (char) i + ": " + counts[i]);
}
Sind Java-Zeichenfolgen ASCII? Ich dachte, es wäre Unicode. In diesem Fall könnte Ihr Code ein Array mit gebundenen Ausnahmen haben. konijn vor 6 Jahren 1
@konijn Ich denke auch, dass sie Unicode sind. Ich habe einfach angenommen, dass wir hier nur ASCII verwenden. Ich habe meine Antwort so bearbeitet, dass sie Unicode unterstützt. Simon Forsberg vor 6 Jahren 2
You don't need to cast `Character.MAX_VALUE` to an int, nor do you need to cast `chartAt` to an int. Internally they are represented as numbers and will work just fine. You can even use `char i` instead of `int i` in your printing loop to avoid the cast to `char` there as well. The nice thing about making it an array like this is that it can make for very readable code. You can get the count for any char by just saying `counts['a']` to get the count for 'a'. cbojar vor 6 Jahren 3
9
palacsint
  1. Actually, there is an even better structure than maps and arrays for this kind of counting: Multisets. Documentation of Google Guava mentions a very similar case:

    The traditional Java idiom for e.g. counting how many times a word occurs in a document is something like:

    Map<String, Integer> counts = new HashMap<String, Integer>();
    for (String word : words) {
      Integer count = counts.get(word);
      if (count == null) {
        counts.put(word, 1);
      } else {
        counts.put(word, count + 1);
      }
    }
    

    This is awkward, prone to mistakes, and doesn't support collecting a variety of useful statistics, like the total number of words. We can do better.

    With a multiset you can get rid of the contains (or if (get(c) != null)) calls, what you need to call is a simple add in every iteration. Calling add the first time adds a single occurrence of the given element.

    String input = "Hello world!";
    
    Multiset<Character> characterCount = HashMultiset.create();
    for (char c: input.toCharArray()) {
        characterCount.add(c);
    }
    for (Entry<Character> entry: characterCount.entrySet()) {
        System.out.println(entry.getElement() + ": " + entry.getCount());
    }
    

    (See also: Effective Java, 2nd edition, Item 47: Know and use the libraries The author mentions only the JDK's built-in libraries but I think the reasoning could be true for other libraries too.)

  2. int length = sample.length();
    ....
    for (int i = 0; i < length; i++) {
        char c = arraysample[i];
    

    You could replace these three lines with a foreach loop:

    for (char c: arraysample) {
    
  3. int length = sample.length();
    ....
    for (int i = 0; i < length; i++) {
        char c = arraysample[i];
    

    You don't need the length variable, you could use sample.length() in the loop directly:

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

    The JVM is smart, it will optimize that for you.

  4. char arraysample[] = sample.toCharArray();
    int length = sample.length();
    for (int i = 0; i < length; i++) {
        char c = arraysample[i];
    

    It's a little bit confusing that the loop iterating over arraysample but using sample.length() as the upper bound. Although their value is the same it would be cleaner to use arraysample.length as the upper bound.

4
BenVlodgi

Yes... there is a simpler way. You have two choices, but each about the same. Use an Array, or a Map. The more advanced way of doing this would certainly be with a Map.

Think about a map as a type of array where instead of using an integer to index the array you can use anything. In our case here we'll use char as the index. Because chars are ints you could just use a simple array in this case, and just mentally think of 'a' as 0, but we're going to take the larger step today.

String sample = "Hello World!";

// Initialization
Map <Character, Integer> counter = new HashMap<Character, Integer>();
for(int c = 'a'; c <= 'z'; c++){
    counter.put((Character)c, 0);
}

// Populate
for (int i = 0; i < sample.length(); i++){
    if(counter.containsKey(sample.charAt(i)))
        counter.put(sample.charAt(i), counter.get(sample.charAt(i)) + 1 );
}

Now anytime you want to know how many of whatever character there was just call this method

int getCount(Character character){
    if(counter.containsKey(character))
        return counter.get(character);
    else return 0;
}

Note: This only will work for counting punctuation.

Ihr Code wirft `NullPointerException` für` counter.get (s.charAt (i)) + 1`, wenn char nicht `'a' .. 'z'` :(` null + 1' wirft. Simon Forsberg vor 6 Jahren 0
@ SimonAndré Forsberg war gerade dabei, das zu beheben, und notiert, dass dies nur Gegenbuchstaben sind BenVlodgi vor 6 Jahren 0
`containsKey (i)`? Das klingt nach einem klaren Fehler. Roland Illig vor einem Jahr 0
0
Joydeep Bhattacharya

Die Verwendung einer funktionalen Programmierung kann dieses Problem sogar stark vereinfachen.

public static void main(String[] args) {

    String myString = "hello world";

    System.out.println(
        myString
            .chars()
            .mapToObj(c -> String.valueOf((char) c))
            .filter(str -> !str.equals(" "))
            .collect(Collectors.groupingBy(ch -> ch, Collectors.counting()))

    );
}

Zuerst erhalten wir den Strom von Ganzzahlen aus der Zeichenfolge

myString.chars()

Als Nächstes transformieren wir die Ganzzahlen in einen String

mapToObj(c -> String.valueOf((char) c))

Dann filtern wir die Zeichen heraus, die wir nicht berücksichtigen müssen. Zum Beispiel haben wir die Leerzeichen gefiltert.

filter(str -> !str.equals(" "))

Dann sammeln wir sie schließlich gruppiert nach den Charakteren und zählen sie

collect(Collectors.groupingBy(ch -> ch, Collectors.counting()))
Warum müssen Sie die Zeichen in Strings konvertieren? Warum verwenden Sie nicht .codePoints () anstelle von .chars ()? Roland Illig vor einem Jahr 0
Wofür steht die Variable "p"? Roland Illig vor einem Jahr 0
Entschuldigung für dieses p, geändert in ch, das den Charakter kennzeichnet Joydeep Bhattacharya vor einem Jahr 0