如何创建自定义比较器来对编号系统进行排序

How to create a custom comparator to sort a numbering system

这是我目前的代码:

package Demo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Demo {

    public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<String>();

        list.add("3.3.x");
        list.add("1.2.x");
        list.add("2.3.x");

        VersionComparator x = new VersionComparator();

        Collections.sort(list, x );

        for(String str : list)
            System.out.println(str);

    }

    static class VersionComparator implements Comparator {
        public int compare(String str1, String str2) {

            String firstNumberStringOne = str1.split(".")[0]; 
            String firstNumberStringTwo = str2.split(".")[0];  
            String secondNumberStringOne = str1.split(".")[1]; 
            String secondNumberStringTwo = str2.split(".")[1];  

            return;
        }

        @Override
        public int compare(Object o1, Object o2) {
            // TODO Auto-generated method stub
            return 0;
        }
    }
}

我想按照出现在句点之前的第一个数字对列表中的项目进行排序。如果这两个数字相等,则转到第二个数字并比较这些数字。如果等于 return 他们。

我不知道如何使用比较器。我试图实现它,但编译器抱怨我需要在第二个比较方法中添加覆盖。我也不知道如何根据 returned 的方式进行比较。我知道如果它等于那么它 return 是 0 小于它 return 是 -1 并且大于 1。但是在编码方面我不知道程序是如何知道的如何排序。

您的 VersionComparator class 正在实现 Comparator 接口的原始形式,其中 compare 方法将占用 2 Object 秒而不是 2 Strings.

通过提供 String 作为类型参数来实现接口。然后编译器将识别您的 compare 方法,将 String 作为参数作为接口的正确实现。您不需要 compare 方法占用 Object 秒。

static class VersionComparator implements Comparator<String> {

您当然需要在 compare method 中实现比较逻辑,如果 str1 比较小于,则返回 int 小于 0、0 或大于 0,根据您的自定义排序顺序等于或大于 str2

 public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<String>();
    list.add("3.3.x");
    list.add("1.2.x");
    list.add("1.11.x");
    list.add("1.1.x");
    list.add("2.3.x");

    Collections.sort(list, new VersionComparator());

    for(String str : list)
       System.out.println(str);

}

static class VersionComparator implements Comparator<String> {
    //Temporary Cache Map to hold Split String value. String as Key and Split String array as value is this in this map.
    Map<String, String[]> mCacheMap = new HashMap<>();

    @Override
    public int compare(String string1, String string2) {

        if(!mCacheMap.containsKey(string1)){
            //Put Split String of string1 to map if it does not contain it.
            mCacheMap.put(string1, string1.split("\."));
        }
        if(!mCacheMap.containsKey(string2)){
           //Put Split String of string2 to map if it does not contain it.
           mCacheMap.put(string2, string2.split("\."));
        }
        //Get First Digit of first string1 from Map
        Integer string1Val1 = Integer.valueOf(mCacheMap.get(string1)[0]); 
        //Get First Digit of second string2 from Map            
        Integer string2Val1 = Integer.valueOf(mCacheMap.get(string2)[0]);

        //Compare Both Digit. compareTo Method return a negative integer, zero, or a positive integer as first Integer value is less than, equal to, or greater than the seconf Integer value.
        int cmp = string1Val1.compareTo(string2Val1);

        if( cmp != 0 ){
            return cmp;
        }else {
            //If First digit of both string is same compare second digit. 
            Integer string1Val2 = Integer.valueOf(mCacheMap.get(string1)[1]); 
            Integer string2Val2 = Integer.valueOf(mCacheMap.get(string2)[1]); 
            return string1Val2.compareTo(string2Val2);
        }

    }
}

结果:

1.1.x
1.2.x
1.11.x
2.3.x
3.3.x

您的代码几乎没有问题:

  1. 您正在使用原始类型比较器

    class VersionComparator implements Comparator // no <Type> here
    

    因此 Comparator<T> 的编译器将尝试将 Object 用作 T。这意味着它会将 compare(T t1, T t2) 方法编译为 compare(Object t1, Object t2)

    如果您希望该方法编译为 compare(String t1, String o2),那么

    • 它只接受 String 个参数
    • 它可以在内部使用像 length()
    • 这样的字符串方法

    通过

    <String>设置为通用类型
    class VersionComparator implements Comparator<String>
    

    现在编译器会知道 TString

  2. 当您调用 split(".") 时,您不是在点上拆分,而是在 任何字符 上拆分(行分隔符除外),因为 split 使用正则表达式 (regex),在正则表达式中 . 表示行分隔符旁边的任何字符。因此,在开始时您将获得空元素数组,这些元素随后将被清除,因为 split(regex) 删除了空尾随字符串。更多信息在这里:.

    要解决此问题,您需要使用 "\.".

  3. 转义 .

这应该涵盖您代码中的主要问题。但是,如果您想创建不错的解决方案,请考虑避免排序 Strings 而是您自己的实例 Version class.
这种方法的优点是,您不必每次比较两个字符串时都将 String 解析为 int(这可能代价高昂),但您可以将 "1.2.3" 的解析版本存储为数组 [1, 2, 3] 并在需要时重复使用。
Version class 也可以实现 Comparable<Vector> 来提供默认的比较方法。

因此您的代码看起来更像:

class Version implements Comparable<Version> {

    private String versionStr;
    private int[] arr;

    public String getVersionStr() { return versionStr; }

    @Override public String toString() { return versionStr; }

    @Override
    public int compareTo(Version other) {

        int result = Integer.compare(arr[0], other.arr[0]);

        if (result != other)
            return result;

        return Integer.compare(arr[1], other.arr[1]);
    }

    public Version(String versionStr) {
        this.versionStr = versionStr;
        this.arr = Stream.of(versionStr.split("\."))
                .limit(2)//get only two first elements
                .mapToInt(Integer::parseInt)//convert String to int
                .toArray();//create array with integers
    }

}

class Demo {

    public static void main(String[] args) {

        List<Version> list = new ArrayList<Version>();

        list.add(new Version("3.3.x"));
        list.add(new Version("1.2.x"));
        list.add(new Version("1.11.x"));
        list.add(new Version("2.3.x"));

        Collections.sort(list);//with use default order provided by compareTo(Version other)

        for (Version str : list)
            System.out.println(str);
    }
}