Java 比较相同的字符会得到不同的结果

Java 比较相同的字符会得到不同的结果,java,count,Java,Count,我试图制作一个程序,统计用户输入短语中字母的所有实例。例如,短语“Hello”将输出“h:1”、“e:1”、“l:2”、“o:1” 我已经学会了如何查找和计数所有字母,除了“a”。当我多次将“a”与其自身进行比较时,它每次都返回不同的值(因此短语“aaaa”将给出a:1、b:1、c:1、d:1) 以下是我使用的代码: int[]countLetter=newint[26]; 字符[]字母表={'a','b','c','d','e','f','g','h','i','j','k','l','m',

我试图制作一个程序,统计用户输入短语中字母的所有实例。例如,短语“Hello”将输出
“h:1”、“e:1”、“l:2”、“o:1”

我已经学会了如何查找和计数所有字母,除了
“a”
。当我多次将
“a”
与其自身进行比较时,它每次都返回不同的值(因此短语
“aaaa”
将给出
a:1、b:1、c:1、d:1
) 以下是我使用的代码:

int[]countLetter=newint[26];
字符[]字母表={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
短语=短语.toLowerCase();
字符串a=“a”;

对于(int i=0;i您永远不应该依赖
compareTo
的确切返回值,除非它是
0
。如果您想将字符
a
b
c
等转换为数组的索引,最好的方法是找到它们之间的差异
a
。这样
a
就被转换为
0
b
1
等:

for(int i=0;i
我建议使用另一种方法,使用a可能是解决此问题的更好方法,地图可以在每个条目中存储2个内容,因此在键中可以存储短语的字符和字符的实例数作为值,下面是一个带有注释的示例:

public static void main(String[] args) {
        String phrase = "hello";
        HashMap<Character, Integer> map = new HashMap<Character, Integer>(); // Define a map, key type character, value type integer
        phrase = phrase.toLowerCase();

        for (int i = 0; i<phrase.length(); i++ ) { // iterate phrase
            char c = phrase.charAt(i); // get current character

            if(map.containsKey(c)) // if key already exists in the map
                map.put(c, map.get(c) + 1); // increment the current value by 1 for this character
            else // if key doesn't exists in the map yet
                map.put(c, 1); // add the character with a value of 1
        }

        for (Map.Entry<Character, Integer> entry : map.entrySet()) { // iterate map
            System.out.println(entry.getKey() + ": " + entry.getValue()); // print key and value
        }
    }
输入:
“aaaa”

输出:

e: 1
h: 1
l: 2
o: 1
a: 4

这是因为
compareTo
比较整个字符串,因此如果该字符串连续包含相同的字符,结果将发生变化。在代码中,您将
compareTo
phrase.substring(i)
进行比较,以便发送整个字符串。
如果要使用
compareTo
替换
phrase.substring(i)
by
phrase.charAt(i)+“

但实际上,您永远不应该将代码基于
compareTo
的返回值。相反,使用字符本身,因为字符是一个数字。

代码中的错误是因为compareTo返回结果的方式。正如Mureinik所说,“您永远不应该依赖compareTo的确切返回值”。我将尝试一下去解释哪里出了问题

如果两个字符串不同,则要么它们在某个索引处具有不同的字符,而该索引是两个字符串的有效索引,要么它们的长度不同,或者两者都不同。如果它们在一个或多个索引位置具有不同的字符,则k是此类索引的最小值。然后,compareTo方法返回

    return str1.charAt(k) - str2.charAt(k);
如果索引位置不存在差异,则按字典顺序,较短的字符串优先于较长的字符串。在这种情况下,compareTo返回字符串长度的差异

    return str1.length() - str2.length();
当短语字符串为“aaaaa”时,对于0-4之间的不同值,会发生这种情况

    //when i = 0
    
    a.compareTo(phrase.substring(i))  
    
    //"a".compareTo("aaaaa")
    //length of "a" - length of "aaaaaa"
    //which is -4
将它与-1相乘,就像你所做的那样,-4变为4,这是字母“e”的索引。你可以检查i的其他值,你就会明白这就是为什么d,c,b和一个计数器等于1

我希望我帮你找到了错误。 有关compareTo()的更多详细信息,请查看此链接

如果允许您使用lambda,您的程序将大大缩短:


创建地图:

Map<Character,Long> counts = phrase.chars().boxed().collect(
    groupingBy( t -> (char)(int)t, counting() ) );

获取:
e:1,h:1,l:2,o:1

您基本上使用的是
String.compareTo
,但这种方式非常奇怪,这并不是您想要的。请考虑一下您试图用表达式
a.compareTo(短语.子字符串(i))实现什么*-1
然后以更简单、更准确的方式编写。提示:您可能希望使用(名称略为隐晦)
count
变量,而不是使用子字符串。。。
Map<Character,Long> counts = phrase.chars().boxed().collect(
    groupingBy( t -> (char)(int)t, counting() ) );
StringJoiner joiner = new StringJoiner( ", " );
for( char c = 'a'; c <= 'z'; c++ )
  if( counts.containsKey( c ) )
    joiner.add( c + ": " + counts.get( c ) );
System.out.println( joiner );