如何对包含数字的String集合进行排序?

我有一个包含这样的数据的字符串向量:

5:34,5:38,17:21,22:11,……

如果我尝试使用Collections.sort(…)合并它; 它会显示如下:

17:21,22:11,5:34,5:38

其实我希望它看起来像这样:

5:34,5:38,17:21,22:11

所以我想根据冒号“:”之前的数字对元素进行排序,然后如果某些元素在“:”之前具有相同的数字,则根据“:”之后的数字对它们进行排序。

最简单的方法是什么?

您可以创建自定义Comparator来拆分String并将其解析为两个整数, 也可以创建一个定制类来表示每个String并将其存储在Collection 。 我赞成后一种方法,因为你只需要分配/解析一次String的开销; 例如

 public class Data implements Comparable { private final int prefix; private final int suffix; public Data(String str) { String[] arr = str.split(":"); if (arr.length != 2) { throw new IllegalArgumentException(); } this.prefix = Integer.parseInt(arr[0]); this.suffix = Integer.parseInt(arr[1]); } public int compareTo(Data data) { // Should really avoid subtraction in case of overflow but done to keep code brief. int ret = this.prefix - data.prefix; if (ret == 0) { ret = this.suffix - data.suffix; } return ret; } // TODO: Implement equals and hashCode (equals to be consistent with compareTo). public String toString() { return String.format("%d:%d", prefix, suffix); } } 

然后,它只是在Collection中存储一些Data对象的情况; 例如

 List l = new ArrayList(); l.add(new Data("13:56")); l.add(new Data("100:16")); l.add(new Data("9:1")); Collections.sort(l); 

还有一件事 – 你提到你正在使用Vector 。 您应该尽量避免使用Vector / Hashtable因为它们已经被List / Map取代,它们是作为JDK 1.2中的Collections Framework的一部分引入的。

执行此操作的正确方法是不将非字符串值存储为字符串。

集合中的数据具有一些结构和规则,不能是任意字符串。 因此,您不应使用String数据类型。

让我们定义一个名为TwoNumbers的类型(因为我不知道该类型应该代表什么,即使我可以猜到):

 class TwoNumbers implements Comparable { private final int num1; private final int num2; public TwoNumbers(int num1, int num2) { if (num1 <= 0 || num2 <= 0) { throw new IllegalArgumentException("Numbers must be positive!"); } this.num1 = num1; this.num2 = num2; } public static TwoNumbers parse(String s) { String[] parts = s.split(":"); if (parts.length != 2) { throw new IllegalArgumentException("String format must be ':'"); } try { return new TwoNumbers(Integer.parseInt(parts[0]), Integer.parseInt(parts[0])); } catch (NumberFormatException e) { throw new IllegalArgumentException("parts must be numeric!", e); } } public int getNum1() { return num1; } public int getNum2() { return num2; } @Override public int compareTo(TwoNumbers o) { if (o == null) { return 1; } int diff = Integer.compare(o.num1, this.num1); if (diff == 0) { diff = Integer.compare(o.num2, this.num2); } return diff; } } 

compareTo方法作为Comparable接口的实现而存在:它定义了如何对这种类型的对象进行排序。

我使用了final字段(并没有提供setter),因为该类实现了不可变对象 。

这样,您可以直接对数据进行排序,而无需额外的Comparator ,也无需在整个程序中分发所有“拆分和解析”代码。 相反,你有一个类负责处理特定的格式,所有其他代码片段都可以使用它。

这是非常低效的,但它应该做的工作。

 Collections.sort(data, new Comparator(){ public int compare(String a, String b){ String[] as = a.split(":"); String[] bs = b.split(":"); int result = Integer.valueOf(as[0]).compareTo(Integer.valueOf(bs[0])); if(result==0) result = Integer.valueOf(as[1]).compareTo(Integer.valueOf(bs[1])); return result; } }) 

(提示:如果是我的代码,我会优化它以使用子串而不是String.split(),但我太懒了)

创建一个java.util.Comparator并将其提供给sort方法。

实现自己的Comparator类,比较两个值并调用Collections.sort(List list, Comparator c)

实现自己的Comparator并将其作为Colelctions.sort方法的第二个参数。

通常,Java中的对象(包括集合)与其默认的hashCode()和equals()方法进行比较。 对于内置对象和数据类型(如String,Integet等),hashCode()是在内部计算的,因此它们被JLS(Java语言规范)保证使用。

因为我们不能总是依赖于默认/内置对象而我们需要处理我们自己的自定义对象(如Employee,Customer等),所以我们必须覆盖hashCode()和equals()方法,所以我们可以根据自定义类的对象的“BEST”相等来提供true / false。

类似的,sort()涉及一个比较行为,它确实需要一个Comparator(它是一个用比较方法的重写方法实现Comparator接口的类)。 您还应该覆盖比较方法,该方法需要比较两个对象并返回结果(0表示相等,1表示第一个对象大于第二个,2表示情况1的反向)。

现在,您应该以不同的方式处理数据,这远远不同于正常的比较。 您需要将数据拆分为两部分(使用可以执行的拆分方法),然后您可以对两个parats进行单独比较(冒号前的第一部分,冒号后的第二部分)。

最后,您应该为sort方法提供此自定义比较器的实例,最终将对您的自定义数据进行自定义排序:)

我觉得这很简单:

 public class NumericalStringSort { public static void main(String[] args) { List input = Arrays.asList(new String[] {"17:21", "22:11", "5:34", "5:38"}); Collections.sort(input, new NumericalStringComparator()); System.out.println(input); } public static class NumericalStringComparator implements Comparator { public int compare(String object1, String object2) { return pad(object1).compareTo(pad(object2)); } private String pad(String input) { return input.indexOf(":") == 1 ? "0" + input : input; } } } 

刚发现这个(很老)的post和答案并没有完全解决我的问题。 我需要一个更通用的解决方案,因为值是用户输入,类似“abc 1 a 12”和“abc 1 a 1”的内容应按所包含的数字顺序排序。 所以我写了下面的比较器:

 new Comparator() { @Override public int compare(String o1, String o2) { String[] s1=splitNumeric(o1); String[] s2=splitNumeric(o2); for (int x=0;x 

虽然函数splitNumeric定义如下:

  private String[] splitNumeric(String s){ final String numbers="0123456789"; LinkedList out=new LinkedList(); int state=-1; for (int x=0;x 

代码将对字符串进行排序

 "X 124 B" "X 1 Y" "X 111 Z" "X 12 Y" "12:15" "12:13" "12:1" "1:1" "2:2" 

如下:

 "1:1" "2:2" "12:1" "12:13" "12:15" "X 1 Y" "X 12 Y" "X 111 Z" "X 124 B" 

请享用 :)