【问题标题】:sorting collections with string elements in java在java中使用字符串元素对集合进行排序
【发布时间】:2010-09-03 10:41:35
【问题描述】:

我有一个集合...我编写了代码来使用我自己的比较器对值进行排序 我的比较器代码是

private static class MatchComparator implements Comparator<xmlparse> {
    @Override
    public int compare(xmlparse object1, xmlparse object2) {
        String match1 = object1.getMatchId();
        String match2 = object2.getMatchId();
        return match1.compareTo(match2);
    }
}

我会打电话给Collections.sort(list,new MatchComparator());

一切都很好,但我的问题是当我打印时排序列表是错误的......

列表输入

Match19
Match7
Match12
Match46
Match32

排序列表的输出

Match12
Match19
Match32
Match46
Match7

我的预期输出是

Match7
Match12
Match19
Match32
Match46

【问题讨论】:

  • 比较是字典而不是数字,这是你的问题。
  • 我该如何解决这个问题?

标签: java collections


【解决方案1】:

要获得您需要的顺序,您可以在 1 位数字前加上零(例如 Match07 ),或者您必须将字符串拆分为前缀和数字部分,并将排序实现为数字比较

【讨论】:

【解决方案2】:

问题是String.compareTo(..) 逐个字符比较单词。

如果所有字符串都以Match 开头,那么您可以通过以下方式轻松解决此问题:

public int compare(xmlparse object1, xmlparse object2) {
    String match1 = object1.getMatchId();
    String match2 = object2.getMatchId();
    return Integer.parseInt(match1.replace("Match"))
         - Integer.parseInt(match2.replace("Match"));
}

如果它们不是以Match 开头,那么您可以使用正则表达式:

Integer.parseInt(object1.replaceAll("[a-zA-Z]+", ""));

或者

Integer.parseInt(object1.replaceAll("[\p{Alpha}\p{Punch}]+", ""));

最后一点 - 用大写字母命名你的类,camelCase - 即XmlParse 而不是xmlparse - 这就是约定所要求的。

【讨论】:

    【解决方案3】:

    实现一个函数并使用它进行比较:
    而不是

    return match1.compareTo(match2);
    

    使用

    return compareNatural(match1,match2);
    

    这是一个对字符串进行自然比较的函数:

    private static int compareNatural(String s, String t, boolean caseSensitive) {
        int sIndex = 0;
        int tIndex = 0;
    
        int sLength = s.length();
        int tLength = t.length();
    
        while (true) {
            // both character indices are after a subword (or at zero)
    
            // Check if one string is at end
            if (sIndex == sLength && tIndex == tLength) {
                return 0;
            }
            if (sIndex == sLength) {
                return -1;
            }
            if (tIndex == tLength) {
                return 1;
            }
    
            // Compare sub word
            char sChar = s.charAt(sIndex);
            char tChar = t.charAt(tIndex);
    
            boolean sCharIsDigit = Character.isDigit(sChar);
            boolean tCharIsDigit = Character.isDigit(tChar);
    
            if (sCharIsDigit && tCharIsDigit) {
                // Compare numbers
    
                // skip leading 0s
                int sLeadingZeroCount = 0;
                while (sChar == '0') {
                    ++sLeadingZeroCount;
                    ++sIndex;
                    if (sIndex == sLength) {
                        break;
                    }
                    sChar = s.charAt(sIndex);
                }
                int tLeadingZeroCount = 0;
                while (tChar == '0') {
                    ++tLeadingZeroCount;
                    ++tIndex;
                    if (tIndex == tLength) {
                        break;
                    }
                    tChar = t.charAt(tIndex);
                }
                boolean sAllZero = sIndex == sLength || !Character.isDigit(sChar);
                boolean tAllZero = tIndex == tLength || !Character.isDigit(tChar);
                if (sAllZero && tAllZero) {
                    continue;
                }
                if (sAllZero && !tAllZero) {
                    return -1;
                }
                if (tAllZero) {
                    return 1;
                }
    
                int diff = 0;
                do {
                    if (diff == 0) {
                        diff = sChar - tChar;
                    }
                    ++sIndex;
                    ++tIndex;
                    if (sIndex == sLength && tIndex == tLength) {
                        return diff != 0 ? diff : sLeadingZeroCount - tLeadingZeroCount;
                    }
                    if (sIndex == sLength) {
                        if (diff == 0) {
                            return -1;
                        }
                        return Character.isDigit(t.charAt(tIndex)) ? -1 : diff;
                    }
                    if (tIndex == tLength) {
                        if (diff == 0) {
                            return 1;
                        }
                        return Character.isDigit(s.charAt(sIndex)) ? 1 : diff;
                    }
                    sChar = s.charAt(sIndex);
                    tChar = t.charAt(tIndex);
                    sCharIsDigit = Character.isDigit(sChar);
                    tCharIsDigit = Character.isDigit(tChar);
                    if (!sCharIsDigit && !tCharIsDigit) {
                        // both number sub words have the same length
                        if (diff != 0) {
                            return diff;
                        }
                        break;
                    }
                    if (!sCharIsDigit) {
                        return -1;
                    }
                    if (!tCharIsDigit) {
                        return 1;
                    }
                } while (true);
            } else {
                // Compare words
                // No collator specified. All characters should be ascii only. Compare character-by-character.
                do {
                    if (sChar != tChar) {
                        if (caseSensitive) {
                            return sChar - tChar;
                        }
                        sChar = Character.toUpperCase(sChar);
                        tChar = Character.toUpperCase(tChar);
                        if (sChar != tChar) {
                            sChar = Character.toLowerCase(sChar);
                            tChar = Character.toLowerCase(tChar);
                            if (sChar != tChar) {
                                return sChar - tChar;
                            }
                        }
                    }
                    ++sIndex;
                    ++tIndex;
                    if (sIndex == sLength && tIndex == tLength) {
                        return 0;
                    }
                    if (sIndex == sLength) {
                        return -1;
                    }
                    if (tIndex == tLength) {
                        return 1;
                    }
                    sChar = s.charAt(sIndex);
                    tChar = t.charAt(tIndex);
                    sCharIsDigit = Character.isDigit(sChar);
                    tCharIsDigit = Character.isDigit(tChar);
                } while (!sCharIsDigit && !tCharIsDigit);
            }
        }
    }
    

    更好的是here

    【讨论】:

      【解决方案4】:

      比较是字典而不是数字,这是你的问题。在词典排序中,10 在 9 之前。

      See this question for open source implementation solutions。您还可以实现自己的字符串比较,这应该不难。

      【讨论】:

        【解决方案5】:

        您似乎并不期望 String.compareTo() 真正是什么。它执行所谓的词典编纂,但您尝试按数字比较它。您需要修改比较器的代码。

          @Override
                public int compare(xmlparse object1, xmlparse object2) {
                    String match1 = object1.getMatchId();
                    String match2 = object2.getMatchId();
        
                    Long n1 = getNumber(match1);
                    Long n2 = getNumber(match2);
        
                    return n1.compareTo(n2);             
                }
        

        getNumber() 从字符串 "matchXX" 中提取最后一个 nuber

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-09
          • 2015-06-07
          • 2021-11-23
          • 2018-03-18
          • 1970-01-01
          • 2019-04-24
          相关资源
          最近更新 更多