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

4

我有以下可能的地址作为字符串(未排序):

"road 21"
"road 1"
"road 186"
"road +21 / 23"
"road +21 / 19"
"another road 21"
"another road 1"

我希望您能将它们按照我指定的方式进行排序(不要使用默认的字符串排序方式):
another road 1
another road 21
road 1
road 21
road +21 / 19
road +21 / 23
road 186

我该怎么做呢?我可能需要使用自定义比较器,但是我应该如何分割字符串?

我认为“路186”应该在“路+21/19”之前。除非你将+视为数字21的一部分(换句话说,忽略它,因为它不影响数字)。 - forgivenson
这是您正在寻找的吗?http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split(java.lang.String) - user902383
道路186应该在+21之前,并且我确实忽略了“+”。这只是他们在这里有时使用的一种格式。@user902383:我知道正则表达式的拆分存在,但实际上我对如何编写这部分的正则表达式没有任何想法 :)。 - GregD
5个回答

3
我用Java实现了这个程序,一开始看起来可能有些奇怪。如果你有任何问题,请随时问我。
public class SpecialComparator implements Comparator<String> {

   @Override
    public int compare(String arg0, String arg1) {
     // TODO Auto-generated method stub
     String []words1=arg0.split(" ");
     String [] words2 = arg1.split(" ");
     int i = 0;

        if (words1[i].hashCode()>words2[i].hashCode()){
            return 1;
        }
        else if (words1[i].hashCode()<words2[i].hashCode()){
            return -1;
        }
        else if (words1[i].hashCode()==words2[i].hashCode())
            return compare(arg0.substring(i+1, arg0.length()), arg1.substring(i+1,arg1.length()));
        else if (i == Math.min(words1.length,words2.length)-1 && Math.min(words1.length,words2.length) == words1.length){
            return -1;
        }
        else if (i == Math.min(words1.length,words2.length)-1 && Math.min(words1.length,words2.length) == words2.length){
            return 1;
        }
        else if (i == Math.min(words1.length,words2.length)-1 && words1.length == words2.length){
            return 0;
        }
        else{
            return 0;
        }


   }


   public static void main (String[] args){
    ArrayList<String> input = new ArrayList<String>();
    SpecialComparator a = new SpecialComparator();
    input.add("road 21");
    input.add("road 1");
    input.add("road 186");
    input.add("road +21 / 23");
    input.add("road +21 / 19");
    input.add("another road 21");
    input.add("another road 1");
    Collections.sort(input,a);
    for (String ans : input){
        System.out.println(ans);
    }

  }



 }

这个排序完美地解决了我的问题。谢谢!我一直在修改“NaturalOrderComparator”的实现,但既然这个代码能够工作,我就使用你的代码。谢谢。 - GregD
1
做这个练习很有趣。 - tudoricc

1
你的格式似乎是:
  • {name}
  • {number}
  • 可选斜杠字符
  • 第二个可选的{number}。
因此,我会创建一个代表这种格式的对象,具有这些属性:
public class MyInput {
  private String name;
  private Integer firstNumber;
  private Integer secondNumber;
}

然后解析您的输入文件以创建一个 List<MyInput>
最后,您可以创建一个自定义的 Comparator 并调用 Collections.sort(yourList, yourCustomComparator)

0

这可能有点麻烦,但这是我为您的问题提供的解决方案。

List<String> list = Arrays.asList("road 21", "road 1", "road 186",
                "road +21 / 23", "road +21 / 19", "another road 21",
                "another road 1");

        Collections.sort(list, new Comparator<String>() {

            Integer toNumber(String string) {
                try {
                    return Integer.parseInt(string);
                } catch (NumberFormatException e) {
                    return null;
                }
            }

            @Override
            public int compare(String o1, String o2) {
                String[] left = o1.split("\\s+");
                String[] right = o2.split("\\s+");
                for (int i = 0; i < Math.min(left.length, right.length); i++) {
                    String ls = left[i];
                    String rs = right[i];

                    Integer li = toNumber(ls);
                    Integer ri = toNumber(rs);

                    if (li != null && ri != null
                            && li.intValue() != ri.intValue()) {
                        return li.intValue() - ri.intValue();
                    } else if (li != null && ri == null) {
                        return 1;
                    } else if (li == null && ri != null) {
                        return -1;
                    } else if (li == null && ri == null){
                        int compared = ls.compareToIgnoreCase(rs);
                        if (compared != 0) {
                            return compared;
                        }
                    }

                }
                return left.length - right.length;
            }
        });

但是如果您可以接受更改结构,那么请采用Arnaud Denoyelle提出的解决方案。


我实际上无法更改结构。否则,我可能确实更喜欢他的解决方案。 - GregD

0

您也可以尝试以下比较器:

class MyComparator implements Comparator<String> {

    @Override
    public int compare(String o1, String o2) {
        o1 = o1.replace("+", "");
        o2 = o2.replace("+", "");

        String[] a1 = o1.split(" ");
        String[] a2 = o2.split(" ");
        int length = (a1.length > a2.length) ? a2.length : a1.length;

        for (int i = 0; i < length; i++) {
            if (!a1[i].equalsIgnoreCase(a2[i])) {
                if (!isIntegerRegex(a1[i]) || !isIntegerRegex(a2[i])) {
                    return o1.compareTo(o2);
                }
                int f = Integer.parseInt(a1[i]);
                int s = Integer.parseInt(a2[i]);
                return f - s;
            }
        }

        return a1.length - a2.length;
    }

    public boolean isIntegerRegex(String str) {
        return str.matches("^[0-9]+$");
    }
}

然后调用它:

public String[] sortStrings(String[] input) {
    Arrays.sort(input, new MyComparator());
    return input;
}

0

它并不能完美地排序,但几乎可以达到那个程度。猜测在很多情况下都可以使用。 - GregD

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