2010-09-03 47 views
2

我有一个集合排序收藏...我写的代码,用我自己的比较器来排序值 我比较代码在Java字符串元素

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 
+8

比较是字典而不是数字,这是你的问题。 – 2010-09-03 10:43:40

+0

我该如何解决这个问题? – Kandha 2010-09-03 10:44:31

回答

2

实现一个功能,用它来比较:中
代替

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

3

得到你需要的顺序,你既可以用零(如Match07)前缀1项数字或你有以前缀和数字部分分割字符串,并将其作为数字比较来执行排序

+0

我们可以从字符串中得到整数吗? 如果可以如何? – Kandha 2010-09-03 10:48:07

+0

Integer.parseInt(“1234”)转换整数字符串,但必须删除前缀(例如使用子字符串) – 2010-09-03 10:51:01

+0

@Kandhasamy http://download.oracle.com/javase/1.4.2/docs/ api/java/lang/Integer.html#parseInt%28java.lang.String%29 – jensgram 2010-09-03 10:52:41

1

您似乎并不期望String.compareTo()真的是什么。它执行所谓的词典式的comarsion,但你试着用数字来比较它。您需要修改比较器的代码。

@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”

3

问题是,String.compareTo(..)比较字由字符char。

如果所有字符串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}]+", "")); 

最后一点 - 用你的名字命名你的类ppercase,camelCase - 即XmlParse而不是xmlparse--这就是公约规定的。

+0

+1 for“convention dictates”...大声笑 – lalli 2010-09-03 11:15:44