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

发布于 2024-12-10 10:59:23 字数 402 浏览 0 评论 0原文

我有一个字符串向量,其中包含如下数据:

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

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

最简单的方法是什么?

I have a String Vector that contains data like this :

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

If i try to merge this using Collections.sort( ... ); it will appear like this :

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

Actually i want it to appear like this :

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

So i want to sort the elements according to the number before the colon ":" then if some elements have the same number before ":" then sort them according to the number after the ":".

What is the simplest way to do this ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

金橙橙 2024-12-17 10:59:23

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

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

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

class TwoNumbers implements Comparable<TwoNumbers> {
    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 '<num>:<num>'");
        }
        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 字段(并且不提供设置器),因为该类实现了

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

The correct way to do this is to not store non-string values as strings.

The data in your collection has some structure and rules and can't be any arbitrary string. Therefore you should not use the String data type.

Let's define a type called TwoNumbers (because I don't know what the type should represent, even if I could guess):

class TwoNumbers implements Comparable<TwoNumbers> {
    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 '<num>:<num>'");
        }
        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;
    }
}

The compareTo method exists as the implementation of the Comparable interface: it defines how objects of this type are ordered.

I've used the final fields (and don't provide setters), because the class implements immutable objects.

This way you can directly sort your data without an additional Comparator and don't need to distribute all that "split and parse" code all over your program. Instead you have a single class that's responsible for handling that specific format and all the other pieces of code can just use that.

秋风の叶未落 2024-12-17 10:59:23

这是非常低效的,但它应该可以完成工作。

Collections.sort(data, new Comparator<String>(){
    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(),但我太懒了)

This is horribly inefficient, but it should do the job.

Collections.sort(data, new Comparator<String>(){
    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;
    }
})

(Hint: if it were my code, I'd optimize it to use substrings instead of String.split(), but I'm too lazy)

北城半夏 2024-12-17 10:59:23

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

public class Data implements Comparable<Data> {
  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<Data> l = new ArrayList<Data>();
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 中集合框架的一部分。

You could either create a custom Comparator to split the String and parse it into two ints, or create a bespoke class to represent each String and store that in the Collection instead. I favour the latter approach as you only incur the overhead of splitting / parsing the String once; e.g.

public class Data implements Comparable<Data> {
  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); }
}

Then it's simply a case of storing some Data objects in your Collection; e.g.

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

One more thing - You mention you're using a Vector. You should try to avoid using Vector / Hashtable as these have been superseded by List / Map, which were introduced as part of the Collections Framework in JDK 1.2.

浊酒尽余欢 2024-12-17 10:59:23

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

Create a java.util.Comparator and provide it to the sort method.

失退 2024-12-17 10:59:23

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

Implement your own Comparator class that compares two values and call Collections.sort(List list, Comparator c).

回心转意 2024-12-17 10:59:23

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

Implement your own Comparator and give it as second argument to the Colelctions.sort method.

酒中人 2024-12-17 10:59:23

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

由于我们不能总是依赖于默认/内置对象,并且我们需要处理我们自己的自定义对象(如 Employee、Customer 等),因此我们应该重写 hashCode() 和 equals() 方法,因此我们可以根据自定义类的对象的“最佳”相等性来提供真/假。

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

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

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

Generally, objects in Java (including Collections) are compared with their default hashCode() and equals() method. For the built in objects and data types (like String, Integet etc.,) the hashCode() is computed internally and hence they are used as guaranteed by the JLS (Java Language Specification).

As we can't always be dependent upon the default/built in objects and we need to deal with our own custom objects (like Employee, Customer etc.,), we should have to override hashCode() and equals() method, so that we can provide the true/false according to the "BEST" equality of the objects of our custom classes.

Similary, sort() involves a comparison act that indeed needs a Comparator (which is a class implementing the Comparator interface with an overridden method of compare method). You should also override the compare method that takes two Objects to be compared and returns a result (0 for equal, 1 for the 1st object being greater than the second, 2 for the reverse of case 1).

Now, you data should be dealt in a different way which is quite away from the normal comparsion. You need to split the data into two parts (using a split method you can do) and then you can do the individual comparison on the two parats (first part before the colon, second part after the colon).

Finally, you should provide an instance of this custom comparator to the sort method, that will eventually do the custom sorting for your custom data :)

愿得七秒忆 2024-12-17 10:59:23

我认为这很简单:

public class NumericalStringSort {

    public static void main(String[] args) {
        List<String> 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<String> {
        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;
        }
    }
}

I think this is pretty simple:

public class NumericalStringSort {

    public static void main(String[] args) {
        List<String> 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<String> {
        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;
        }
    }
}
星光不落少年眉 2024-12-17 10:59:23

刚刚发现这篇(相当旧的)帖子,答案并没有完全解决我的问题。我需要一个更通用的解决方案,因为这些值是用户输入,并且诸如“abc 1 a 12”和“abc 1 a 1”之类的内容应该按照包含的数字的顺序进行排序。所以我写了以下比较器:

new Comparator<String>() {

        @Override
        public int compare(String o1, String o2) {
            String[] s1=splitNumeric(o1);
            String[] s2=splitNumeric(o2);
            for (int x=0;x<s1.length&&x<s2.length;x++){
                if (!s1[x].equals(s2[x])){
                    if (s1[x].charAt(0)=='N' && s2[x].charAt(0)=='N'){
                        long l1=Long.parseLong(s1[x].substring(1));
                        long l2=Long.parseLong(s2[x].substring(1));
                        return (int)Math.signum(l1-l2);
                    }
                    break;
                }
            }
            return o1.compareTo(o2);
        }
    }

而函数 splitNumeric 定义如下:

   private String[] splitNumeric(String s){
        final String numbers="0123456789";
        LinkedList<String> out=new LinkedList<String>();
        int state=-1;
        for (int x=0;x<s.length();x++){
            if (numbers.contains(s.charAt(x)+"")){
                if (state==1)
                    out.set(out.size()-1,out.getLast()+s.charAt(x));
                else{
                    state=1;
                    out.add("N"+s.charAt(x));
                }
            }
            else{
                if (state==0)
                    out.set(out.size()-1,out.getLast()+s.charAt(x));
                else{
                    state=0;
                    out.add("S"+s.charAt(x)+"");
                }
            }
        }
        return out.toArray(new String[0]);
    }

代码将按

"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"

享受:)

Just found this (quite old) post and the answers didn't quite solve the problem I have. I needed a more generic solution, as the values were user inputs and something like "abc 1 a 12" and "abc 1 a 1" should be sorted in order of the contained number(s). So I wrote the following Comparator:

new Comparator<String>() {

        @Override
        public int compare(String o1, String o2) {
            String[] s1=splitNumeric(o1);
            String[] s2=splitNumeric(o2);
            for (int x=0;x<s1.length&&x<s2.length;x++){
                if (!s1[x].equals(s2[x])){
                    if (s1[x].charAt(0)=='N' && s2[x].charAt(0)=='N'){
                        long l1=Long.parseLong(s1[x].substring(1));
                        long l2=Long.parseLong(s2[x].substring(1));
                        return (int)Math.signum(l1-l2);
                    }
                    break;
                }
            }
            return o1.compareTo(o2);
        }
    }

While the function splitNumeric is defined as follows:

   private String[] splitNumeric(String s){
        final String numbers="0123456789";
        LinkedList<String> out=new LinkedList<String>();
        int state=-1;
        for (int x=0;x<s.length();x++){
            if (numbers.contains(s.charAt(x)+"")){
                if (state==1)
                    out.set(out.size()-1,out.getLast()+s.charAt(x));
                else{
                    state=1;
                    out.add("N"+s.charAt(x));
                }
            }
            else{
                if (state==0)
                    out.set(out.size()-1,out.getLast()+s.charAt(x));
                else{
                    state=0;
                    out.add("S"+s.charAt(x)+"");
                }
            }
        }
        return out.toArray(new String[0]);
    }

The code will sort Strings

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

as follows:

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

Enjoy :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文