使用比较器对包含整数的字符串进行排序

时间:2016-08-18 15:47:35

标签: java regex sorting comparator

我有一个比较器,它对包含字母和数字的字符串数组进行排序,但似乎无法识别以我正在寻找的方式对它们进行排序的正则表达式。

我使用this question作为比较器的参考。

array={string-a01,string-a20,string-a100,string-b01,string-b20,string-b100,string-c01,string-c20,string-c100 etc.}

Collections.sort(array, new Comparator<String>(){       
    public int compare(String o1, String o2) {
        return extractInt(o1) - extractInt(o2);
    }

    int extractInt(String s) {
        String num = s.replaceAll("\\D", "");
        return num.isEmpty() ? 0 : Integer.parseInt(num);
    }
});

for (String element : array) {
    System.out.println(element);
}

在介绍比较器之前,输出是:
string-a01, string-a100, string-a20, string-b01, string-b100, string-b20, string-c01, string-c20, string-c100

此代码产生的输出是:
string-a01, string-b01, string-c01 string-a20, string-b20, string-c20 string-a100, string-b100, string-c100

我希望它产生的输出是:
string-a01, string-a20, string-a100, string-b01, string-b20, string-b100, string-c01, string-c20, string-c100


编辑:编辑澄清。在添加比较器之前,阵列已更改并输出。

3 个答案:

答案 0 :(得分:3)

假设string部分实际上不仅仅是"string"。您可以提取结尾的字母部分和数字部分,并使用复合比较器进行比较:

String[] array = { "string-a20", "string-a01", "string-b01",
    "string-b20", "string-c01", "string-c20",
    "string-a100", "string-b100", "string-c100" };

Pattern p = Pattern.compile("^.*?-([A-Za-z]+)(\\d+)$");

List<String> result = Arrays.stream(array)
    .map(p::matcher)
    .filter(Matcher::find)
    .sorted(Comparator.comparing((Matcher m) -> m.group(1)) // Compare the letter part
        .thenComparingInt(m -> Integer.parseInt(m.group(2)))) // Compare the number part
    .map(m -> m.group(0)) // Map back to String
    .collect(Collectors.toList());

System.out.println(result);

输出:

[string-a01, string-a20, string-a100, string-b01, string-b20, string-b100, string-c01, string-c20, string-c100]

旧版本(不得不重新创建Matcher s):

Arrays.sort(array, new Comparator<String>() {

    Pattern p = Pattern.compile("^.*?-([A-Za-z]+)(\\d+)$");

    @Override
    public int compare(String o1, String o2) {
        Matcher m1 = p.matcher(o1);
        Matcher m2 = p.matcher(o2);

        if(!(m1.find() && m2.find()))
            return 0; // Or throw a format exception

        int comparison = m1.group(1).compareTo(m2.group(1));
        return comparison != 0
            ? comparison 
            : Integer.compare(Integer.parseInt(m1.group(2)), Integer.parseInt(m2.group(2)));
    }

});

答案 1 :(得分:1)

您正在删除extractInt方法中的字母字符,因此您无法在比较中使用它们。

您应该使用 Comparator对其进行排序,这将使用默认的词典排序算法(java.lang.String实现Comparable<String>)对它们进行排序。

示例

// test array
String[] s = {"string-a01","string-a01","string-b01","string-b02","string-c02","string-c02"};

// sorting with null Comparator, will sort if the type implements Comparable - 
// which String does
Arrays.sort(s);

// printing in human-readable form
System.out.println(
    Arrays.toString(s)
);

<强>输出

[string-a01, string-a01, string-b01, string-b02, string-c02, string-c02]

备注

  • 如果您想删除重复项(可能是您对问题的意图 - 不清楚),请将数组元素添加到TreeSet

    Set<String> deduplicated = new TreeSet<>(Arrays.asList(s));
    
  • 如果您的排序算法必须采取行动以使2出现在12之前,那么您需要从元素中提取整数值而不将其删除,并且只有当String s的其余部分相等时才进行比较。

答案 2 :(得分:1)

听起来你想要在&#34;领先的字符串&#34;上排序字符串,即一切都到数字;如果前导字符串相等,则比较后续数字。

将字符串拆分为&#34;字符串&#34;和&#34;整数&#34;你可以先输入&#34;第一个尾随数字&#34;,即字符串中第一个字符的位置,它与字符串末尾之间没有非数字:

int firstTrailingDigit(String s) {
  int i = s.length();
  while (i > 0 && Character.isDigit(s.charAt(i - 1))) {
    --i;
  }
  return i;
}

然后您可以在比较器中使用它:

public int compare(String a, String b) {
  int ftdA = firstTrailingDigit(a);
  int ftdB = firstTrailingDigit(b);

  // Get the leading strings, and compare.
  String sA = a.substring(0, ftdA);
  String sB = b.substring(0, ftdB);
  int compareStrings = sA.compareTo(sB);
  if (compareStrings != 0) {
    // If they're not equal, return the result of the comparison.
    return compareStrings;
  }

  // Get the trailing numbers from the strings, and compare.
  int iA = Integer.parseInt(a.substring(ftdA));
  int iB = Integer.parseInt(b.substring(ftdB));
  return Integer.compare(iA, iB);
}

Ideone demo

输入:

String[] array = {"string-a01","string-a20","string-a100","string-b01","string-b20","string-b100","string-c01","string-c20","string-c100"};

输出:

[string-a01, string-a20, string-a100, string-b01, string-b20, string-b100, string-c01, string-c20, string-c100]