可能包含数字的字符串排序

88

我需要编写一个Java Comparator类来比较字符串,但有一个要求。如果正在比较的两个字符串在开头和结尾相同,并且不同之处是整数,则基于这些整数的数值进行比较。例如,我希望以下字符串按照它们显示的顺序结束:

  • aaa
  • bbb 3 ccc
  • bbb 12 ccc
  • ccc 11
  • ddd
  • eee 3 ddd jpeg2000 eee
  • eee 12 ddd jpeg2000 eee

您可以看到,字符串中可能有其他整数,因此我不能只使用正则表达式来提取任何整数。我考虑从字符串开头开始遍历字符串,直到找到一个不匹配的位,然后从结尾开始遍历字符串,直到找到一个不匹配的位,然后将中间的位与正则表达式"[0-9]+ "进行比较,如果相似,则进行数字比较,否则进行字典比较。

有更好的方法吗?

更新 我认为我无法保证字符串中的其他数字(可能匹配)周围没有空格,或者不同的数字确实有空格。

25个回答

0

简短回答:基于上下文,我无法确定这是个人使用的快速代码还是高盛最新内部会计软件的关键部分,所以我要说:呃。这是一种相当奇特的排序算法;如果可以,请尝试使用更简单的算法。

长回答:

在您的情况下,立即出现的两个问题是性能和正确性。非正式地说,确保它快速,并确保您的算法是总排序

(当然,如果您不排序超过100个项目,您可能可以忽略本段。)性能很重要,因为比较器的速度将是您的排序速度中最大的因素(假设排序算法对典型列表是“理想的”)。在您的情况下,比较器的速度主要取决于字符串的大小。字符串似乎相当短,因此它们可能不会像列表的大小那样占主导地位。

将每个字符串转换为字符串-数字-字符串元组,然后对这个元组列表进行排序,如另一个答案中建议的那样,在某些情况下会失败,因为您显然会有多个数字出现的字符串。

另一个问题是正确性。具体来说,如果您描述的算法将允许 A> B> ...> A,则您的排序将是非确定性的。在您的情况下,我担心可能会出现这种情况,尽管我无法证明。请考虑一些解析案例,例如:
  aa 0 aa
  aa 23aa
  aa 2a3aa
  aa 113aa
  aa 113 aa
  a 1-2 a
  a 13 a
  a 12 a
  a 2-3 a
  a 21 a
  a 2.3 a

0
我的问题是,我有一些列表,其中包含组合的字母数字字符串(例如C22、C3、C5等)、字母字符串(例如A、H、R等)和纯数字(例如99、45等),需要按照A、C3、C5、C22、H、R、45、99的顺序进行排序。我还有重复项需要删除,以便只得到一个条目。
我不仅仅使用字符串,而且要对一个对象进行排序,并使用对象内的特定字段来获得正确的顺序。
对我有效的解决方案是:
SortedSet<Code> codeSet;
codeSet = new TreeSet<Code>(new Comparator<Code>() {

private boolean isThereAnyNumber(String a, String b) {
    return isNumber(a) || isNumber(b);
}

private boolean isNumber(String s) {
    return s.matches("[-+]?\\d*\\.?\\d+");
}

private String extractChars(String s) {
    String chars = s.replaceAll("\\d", "");
    return chars;
}

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

private int compareStrings(String o1, String o2) {

    if (!extractChars(o1).equals(extractChars(o2))) {
        return o1.compareTo(o2);
    } else
        return extractInt(o1) - extractInt(o2);
}

@Override
public int compare(Code a, Code b) {

    return isThereAnyNumber(a.getPrimaryCode(), b.getPrimaryCode()) 
            ? isNumber(a.getPrimaryCode()) ? 1 : -1 
                : compareStrings(a.getPrimaryCode(), b.getPrimaryCode());
                }
            });

它“借用”了我在Stackoverflow上找到的一些代码,再加上我自己的一些调整,使其按照我需要的方式正常工作。

由于需要对对象进行排序、需要比较器以及去重,我不得不采用一个负面的方法,即我必须先将我的对象写入TreeMap,然后再将它们写入TreeSet。这可能会稍微影响性能,但考虑到列表最多只有80个代码,这应该不是问题。


-1
在您提供的示例中,您想要比较的数字周围有空格,而其他数字则没有,那么为什么正则表达式不能起作用呢?
bbb 12 ccc
对比
eee 12 ddd jpeg2000 eee

-1
如果你正在编写一个比较器类,你应该实现自己的compare方法,逐个字符比较两个字符串。这个compare方法应该检查你处理的是字母字符、数字字符还是混合类型(包括空格)。你需要定义混合类型的行为方式,例如数字在字母字符之前还是之后,以及空格的位置等等。

-1
在Linux上,glibc提供了strverscmp()函数,它也可以通过gnulib进行移植。然而,真正的“人类”排序还有许多其他的怪癖,比如将“The Beatles”排序为“Beatles, The”。对于这个通用问题,没有简单的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接