4
char [] array = {a,a,a,b,b,c,c,c,a,d};

I want to count every same element in that array so I can sort it from highest frequency to the lowest one. I want the output become like this:

4 (for a)
2 (for b)
3 (for c)
1 (for d)

I have try this

public static void CountbyChar(String s){
    int [] arr = new int [s.length()];
    char [] c =s.toCharArray();
    for (int i=0;i<c.length;i++){
        arr[i]=1;
        for (int j=i+1;j<c.length;j++){
            if(c[i]==c[j]){
                arr[i]++;
            }
        }
    }
    for (int x:arr){
        System.out.println(x);
    }
}

But I got:

4
3
2
2
1
2
1
1

Where is my fault?

Wojciech Wirzbicki
  • 3,887
  • 6
  • 36
  • 59
husnul
  • 130
  • 3
  • 11
  • 2
    It would be a lot easier to use a Map for this. You could map characters to the number of times they occur. Let me know if this is **NOT** a homework assignment... I'll give you a simple example if you're allowed to use maps. – jahroy Dec 17 '12 at 22:43
  • of course no. I try to learn java. That's why I come here. I will be glad if you show me how to do that. @jahroy – husnul Dec 17 '12 at 22:47
  • An alternative would be sorting the array before processing it, so you can know (if the current element is different from the previous) that you have counted all the instances of the previous element. – SJuan76 Dec 17 '12 at 22:50
  • Just added an answer with a simple example using a Map. – jahroy Dec 17 '12 at 22:57

6 Answers6

3

The problem is that you are creating a new counter for each character in the string, rather than creating one for each possible letter. Essentially, your program counts how many times a character occurs in a string in positions after the current character.

Fixing this issue should be relatively easy: make counters for each letter of the alphabet, and increment them when you see the corresponding letter. Assuming that you do it case-sensitively, you can do it like this:

public static void CountbyChar(String s){
    int [] arr = new int [256];
    for (char c : s.toCharArray()){
        if (c < 256) {
            arr[c]++;
        }
    }
    for (int i = 0 ; i != 256 ; i++) {
        if (arr[i] != 0) {
            System.out.print((char)i);
            System.out.print(" : ");
            System.out.println(arr[i]);
        }
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I was handedly defeated. :P – sdasdadas Dec 17 '12 at 22:47
  • Java `char` type is a 16-bit Unicode code point, not an 8-bit code. Your array is nowhere near large enough unless the input range is restricted to ASCII or some such. – Ted Hopp Dec 17 '12 at 22:48
  • @TedHopp Right, that's why I added a `if (c < 256)` check. In real life, I would probably use an array of `65535` (after all, 256K of memory is not much, by the standards of today's hardware) but OP's example strongly suggests that the assignment is using the ASCII subset of the UNICODE codepoints. – Sergey Kalinichenko Dec 17 '12 at 22:54
  • yeah. It works. But now I have a new problem how to print it based on the frequency not the character. – husnul Dec 17 '12 at 23:01
  • @husnul Create a small class with two fields - `char ch` and `int count`, make a list of instances of that class, one per character that you find, sort by frequency, and print the results. [Here is a link to](http://stackoverflow.com/a/4805676/335858) a good answer explaining how to sort lists of objects using a custom comparator. In your case, the comparator would take a frequency object instead of a `Person` object. – Sergey Kalinichenko Dec 17 '12 at 23:06
3

Here's a simple example of how to use a Map to achieve the same result:

char[] inputChars = { 'a', 'b', 'c', 'a', 'a', 'b', 'a', 'a' };

//  create a map whose keys will be the chars in the array and
//  whose values will represent the number of times each char 
//  occurs in the input array.

Map<Character, Integer> countMap = new HashMap<Character, Integer>();

// loop over the input array and populate the map

for (char c : inputChars) {
    if (countMap.containsKey(c)) {
        int currentCount = countMap.get(c);
        countMap.put(c, currentCount + 1);
    }
    else {
        countMap.put(c, 1);
    }
}

// test it

for (char c : countMap.keySet()) {
    print(c + ": " + countMap.get(c));
}

More reading on Maps:

jahroy
  • 22,322
  • 9
  • 59
  • 108
1

This is because you're treating each character's position independently - which means you're only counting after the character occurs.

EDIT: Since I was beaten to the punch, here's a correct example:

public int[] charFrequency(String s) {
    int[] frequencies = new int[256];
    for (char c : s.toCharArray()) {
        if (c > 0 && c < 256) {
            frequencies[c]++;
        }
    }
    return frequencies;
}
sdasdadas
  • 23,917
  • 20
  • 63
  • 148
  • 1
    Works fine for ASCII characters, but what if the array all of a sudden includes something from Japanese, Arabic, etc.? – Ted Hopp Dec 17 '12 at 22:50
1

You want to iterate your array and build a map of the elements such that each map entry is a count of the number of times you have encountered that key. So if the key doesn't exist in the map, add it with a count of 1, otherwise update the map with the incremented count for that key.

Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
1

You are basically having a counter for each letter in the string, you should keep one Map and accumulate the count for each letter.

Something like this should be sufficient

public static void CountbyChar(String s){
        HashMap<Character, Integer> letterCountMap = new HashMap<Character, Integer> ();
        char [] c =s.toCharArray();
        for (int i=0;i<c.length;i++){
            Integer count = 0;
            if (letterCountMap.containsKey(c[i])){
                count = letterCountMap.get(c[i]) + 1 ;
            }else {
                count = 1;
            }
            letterCountMap.put(c[i], count);
        }
        for (Map.Entry<String, String> entry : letterCountMap.entrySet())
        {
            System.out.println(entry.getValue() + "( for" + entry.getKey() + " )");
        }
    }
Amar
  • 11,930
  • 5
  • 50
  • 73
0

Here is implementation with map:

public static void countbyChar(String s){
    Map<Character, Integer> map = new HashMap<Character,Integer>();

    for (char c : s.toCharArray()){
         Integer count = map.get(c);
         if (count == null) {
            map.put(c, 1);
         }
         else {
            map.put(c, count + 1);
         }
    }

    for (Map.Entry<Character, Integer> entry : map.entrySet())
    {
        System.out.println(entry.getKey().toString() + "/" + entry.getValue().toString());
    }
}
Marcin Szymczak
  • 11,199
  • 5
  • 55
  • 63