简体   繁体   English

在char []中搜索char与使用String.indexOf()方法搜索String之间有什么区别?

[英]What is the difference between searching for a char in a char[] vs searching for a String using the String.indexOf() method?

private static int getTotalWordValue(String word) {
    int totalWordValue = 0;

    // Code that produces correct results.
    for(int i=0; i < alpha.length(); i++) {
        char letter = alpha.charAt(i);
        for(char ch: word.toCharArray()) {
            if(letter == ch) {
                totalWordValue += i+1;
            }
        }
    }

    // Code that produces incorrect results.
    totalWordValue = 0;
    for(int i=0; i < alpha.length(); i++) {
        String letter = String.valueOf(alpha.charAt(i)); // <-- here?
        if(word.indexOf(letter) != -1) {
            totalWordValue += i+1;
        }
    }

    return totalWordValue;
}

Upon running the above code to solve Project Euler Problem 42 , I am getting different results. 运行上述代码以解决Project Euler问题42时 ,我得到了不同的结果。 The first 'for' loop shown above outputs the correct results and the second 'for' loop outputs incorrect results. 上面显示的第一个“ for”循环输出正确的结果,第二个“ for”循环输出错误的结果。

The above code takes a String and returns its word value. 上面的代码接受一个String并返回其word值。 For example, the word SKY will return a word value of 55 as the letters in this word add as follows (starting at 1): 例如,单词SKY将返回单词值55,因为该单词中的字母按如下方式添加(从1开始):

  • S = 19 (19th position of the alphabet) S = 19(字母的第19个位置)
  • K = 11 (11th position of the alphabet) K = 11(字母的第11个位置)
  • Y = 25 (25th position of the alphabet). Y = 25(字母的第25个位置)。

19 + 11 + 25 = 55. 19 + 11 + 25 = 55。

I have reduced the problem to the above code and do not understand why this occurs. 我已将问题简化为上述代码,并且不明白为什么会发生这种情况。 Perhaps I have missed an important piece of information as it relates to the Java String class and its methods. 也许我错过了与Java String类及其方法有关的重要信息。

I am running Java 8 in Eclipse Neon.3 Release (4.6.3) on Windows 10. 我正在Windows 10的Eclipse Neon.3 Release(4.6.3)中运行Java 8。

The two pieces of code are entirely different. 这两段代码完全不同。

In both cases you have an outer loop which serves up each character of the string alpha in the variable letter . 在这两种情况下,您都有一个外部循环,该循环为可变letter中的字符串alpha每个字符提供服务。

In the first case, you then have an inner loop which runs through every character of the string word and counts every matching occurrence of letter . 在第一种情况下,您将拥有一个内部循环,该循环遍历字符串word 每个字符并计算letter 每个匹配出现。 When the inner loop has counted every occurrence of letter in word , the outer loop moves on to the next letter . 当内循环计算出word 每个 letter出现次数时,外循环将移至下一个letter

In the second case, there's no inner loop. 在第二种情况下,没有内部循环。 Each time around the outer loop you use word.indexOf(letter) to try to find the index of the first occurrence of letter in word . 每次围绕外循环,您都使用word.indexOf(letter)尝试查找word 第一个出现letter的索引。 If there is one, you advance your count. 如果有一个,则增加计数。 Either way, you're now done with that letter and the outer loop moves on to the next letter . 无论哪种方式,您都已经完成了该letter ,外循环继续到下一个letter There might have been other occurrences of letter in word , but this case didn't try to find them and count them. word可能还存在其他letter ,但是这种情况并未尝试找到它们并对其进行计数。

The word value is incorrect in the second implementation for words that contain some letters multiple times. 在第二种实现中,对于多次包含某些字母的单词,单词值不正确。 For example for WOOD, the first method will calculate 3 + 14 + 14 + 22, but the second will calculate 3 + 14 + 22. 例如,对于WOOD,第一种方法将计算3 + 14 + 14 + 22,但是第二种方法将计算3 + 14 + 22。

Why? 为什么? The first method iterates over characters of the word : 第一种方法遍历单词的字符:

 for(char ch: word.toCharArray()) { if(letter == ch) { totalWordValue += i+1; } } 

The second method iterates over characters of the alphabet : 第二种方法迭代字母的字符

 for(int i=0; i < alpha.length(); i++) { String letter = String.valueOf(alpha.charAt(i)); // <-- here? if(word.indexOf(letter) != -1) { totalWordValue += i+1; } } 

So in the example of "WOOD", "O" will be counted only once, instead of twice. 因此,在“ WOOD”的示例中,“ O”将仅计数一次,而不是两次。


As an aside, the conversion to String is pointless here: 顺便说一句,到String的转换在这里毫无意义:

 String letter = String.valueOf(alpha.charAt(i)); if(word.indexOf(letter) != -1) { 

A better way to write the same thing: 编写相同内容的更好方法:

char letter = alpha.charAt(i);
if (word.indexOf(letter) != -1) {

(But the implementation would still be incorrect.) (但是实现仍然是不正确的。)


Finally, if the alphabet is English AZ, then a faster implementation is possible: 最后,如果字母是英语AZ,则可以实现更快的实现:

int totalWordValue = 0;
for (char c : word.toCharArray()) {
  if ('A' <= c && c <= 'Z') {
    totalWordValue += (c - 'A') + 1;
  }
}

return totalWordValue;

indexOf has 4 overloaded method and one of them except character argument and return the index of the first occurrence of the character in the character sequence. indexOf有4个重载方法,其中一个重载方法( character参数除外),并返回字符序列中字符首次出现的索引。

Now, coming to you question. 现在,问您一个问题。 In your scenario indexOf and charAt will behave same because you are passing ONLY character. 在您的方案中indexOfcharAt行为相同,因为您仅传递了字符。 And, since internally, But, imagine, you have a String and you wanted to check and get the index of it from another long String . 而且,从内部开始,但是,想象一下,您有一个String并且想要从另一个长String进行检查并获取它的索引。 Then what would you do ? 那你会怎么做? There comes indexOf indexOf

I know this doesn't necessarily solve your question about the differences between the mentioned methods, but others have answered well enough on that. 我知道这并不一定能解决您关于上述方法之间的区别的问题,但是其他人对此已回答得足够好。

You want the sum of the positions in the alphabet of the letters of a String? 您想要一个字符串字母的字母位置的总和吗? We can do that in one loop with some arithmetic, without the added overhead of the inner loops or the alpha constant. 我们可以使用某种算法在一个循环中完成此操作,而无需增加内部循环或alpha常数的开销。

Like so: 像这样:

public static int getWordValue(String word) {
    int value = 0; //total word value
    for(char c : word.toLowerCase().toCharArray()) { //iterate over character array of lower case string
            int charAsInt = (int) c; //cast char to int, giving the ASCII value
            if(charAsInt <= 122 && charAsInt >= 97) { //122 is the ASCII value of 'z', and 97 is 'a'
                value += (charAsInt - 96); //only subtract 96 because we want 'a' to be 1, not 0
            }
     }
    return value;
}

If the reason this works is unclear to you now, it will become evident upon examining an ASCII to decimal table. 如果您现在尚不清楚这种工作的原因,那么在检查ASCII到十进制表后就会很明显。 Let's check one out. 让我们来看看。

ASCII到十进制表

Make note of the values of lowercase 'a' and lowercase 'z'. 记下小写字母“ a”和小写字母“ z”的值。 They are our lower and upper bounds, respectively. 它们分别是我们的下限和上限。 We simply loop over each lower case character, converting it to its ASCII decimal value with an int cast. 我们只需循环遍历每个小写字符,并使用int强制转换将其转换为ASCII十进制值。 Then we subtract our ASCII value by the value of 'a', minus one. 然后,我们将ASCII值减去“ a”的值再减去一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM