在数组中计算元素出现的次数

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

我希望能够计算数组中每个相同元素的数量,以便将其按照出现频率从高到低进行排序。 我希望输出结果如下:
4 (for a)
2 (for b)
3 (for c)
1 (for d)

我已经尝试过这个

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);
    }
}

但是我得到了:
4
3
2
2
1
2
1
1

我的错误在哪里?

2
使用Map会更容易。您可以将字符映射到它们出现的次数。如果这不是一项作业任务,请告诉我...如果允许使用映射,则我会给您一个简单的示例。 - jahroy
当然不是。我正在尝试学习Java,这就是我来这里的原因。如果您能向我展示如何做到这一点,我将非常高兴。@jahroy - husnul
另一种方法是在处理数组之前对其进行排序,这样您就可以知道(如果当前元素与上一个元素不同),您已经计算了先前元素的所有实例。 - SJuan76
刚刚添加了一个使用Map的简单示例答案。 - jahroy
6个回答

3
问题在于你为字符串中的每个字符都创建了一个新的计数器,而不是为每个可能的字母创建一个。实际上,你的程序计算的是当前字符之后出现的每个位置中该字符出现的次数。
修复这个问题应该相对容易:为每个字母计数器创建一个计数器,并在看到相应的字母时递增它们。假设你进行大小写敏感的统计,可以像这样做:
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]);
        }
    }
}

我被轻松打败了。 :P - sdasdadas
Javaдёӯзҡ„charзұ»еһӢжҳҜдёҖдёӘ16дҪҚUnicodeд»Јз ҒзӮ№пјҢиҖҢдёҚжҳҜ8дҪҚд»Јз ҒгҖӮйҷӨйқһиҫ“е…ҘиҢғеӣҙиў«йҷҗеҲ¶дёәASCIIжҲ–зұ»дјјзҡ„еҶ…е®№пјҢеҗҰеҲҷжӮЁзҡ„ж•°з»„иҝңиҝңдёҚеӨҹеӨ§гҖӮ - Ted Hopp
@TedHopp 对的,这就是为什么我添加了一个 if (c < 256) 检查的原因。在实际应用中,我可能会使用一个 65535 的数组(毕竟,按照今天硬件的标准,256K 的内存并不算多),但 OP 的示例强烈暗示该赋值正在使用 UNICODE 码点的 ASCII 子集。 - Sergey Kalinichenko
是的,它可以工作。但现在我有一个新问题,如何根据频率而不是字符打印它。 - husnul
@husnul 创建一个带有两个字段 - char chint count 的小类,为您找到的每个字符创建一个该类的实例列表,按频率排序并打印结果。这里是一个链接 ,其中提供了一个很好的答案,解释如何使用自定义比较器对对象列表进行排序。在您的情况下,比较器将采用频率对象而不是 Person 对象。 - Sergey Kalinichenko

3
这是一个使用Map实现相同结果的简单示例:
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));
}

更多有关地图的阅读资料:


1
你想迭代你的数组并构建一个映射,使得每个映射条目都是你遇到该键的次数的计数。因此,如果该键不存在于映射中,则将其添加,并将其计数为1,否则更新该键的计数后再更新映射。

1

这是因为您正在独立处理每个字符的位置 - 这意味着您只在字符出现后进行计数。

编辑:由于我被打败了,这里提供一个正确的例子:

public int[] charFrequency(String s) {
    int[] frequencies = new int[256];
    for (char c : s.toCharArray()) {
        if (c > 0 && c < 256) {
            frequencies[c]++;
        }
    }
    return frequencies;
}

1
对于ASCII字符来说工作得很好,但如果数组突然包含了日语、阿拉伯语等内容怎么办? - Ted Hopp

1

你基本上为字符串中的每个字母都有一个计数器,你应该保留一个Map并累加每个字母的计数。

类似这样的代码应该就足够了

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() + " )");
        }
    }

0

这是使用 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());
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接