排序版本号

时间:2016-12-17 12:02:45

标签: java sorting version

我的下面的代码应该将版本号排序为正确的顺序。在大多数情况下它可以工作,但它失败了一个我无法访问的隐藏测试用例。鉴于有任何边缘情况,你可以看到我可能会失踪。

import java.util.*;

public class Answer {   
public static void main(String[] args)
{
    //Testing 
    String[] versions = {"0.0.0","0","0.0","1.113","0.0.0.1","2.0.0","1.2","2","0.1","1.2.1","1.1.1","2.0"};
    String[] results = answer(versions);
    for(int i =0; i<results.length;i++)
    {
        System.out.println(results[i]);
    }   
}
public static String[] answer(String[] l) { 

    String temp = new String();
    //Insertion sort on the given array to assign correct version numbers
    for (int i = 1; i < l.length; i++) {
        for(int j = i ; j > 0 ; j--){
            if(compareVersion(l[j],l[j-1])<0){
                temp = l[j];
                l[j] = l[j-1];
                l[j-1] = temp;
            }
        }
    }
    return l;
} 
//Will compare version numbers breaking it apart into a String array
public static int compareVersion(String version1, String version2) {
String[] arr1 = version1.split("\\.");
String[] arr2 = version2.split("\\.");

int i=0;
while(i<arr1.length || i<arr2.length){
    if(i<arr1.length && i<arr2.length){
        if(Integer.parseInt(arr1[i]) < Integer.parseInt(arr2[i])){
            return -1;
        }else if(Integer.parseInt(arr1[i]) > Integer.parseInt(arr2[i])){
            return 1;
        }
        else if(Integer.parseInt(arr1[i]) == Integer.parseInt(arr2[i]))
        {
            int result = specialCompare(version1,version2);
            if(result != 0)
            {
                return result;
            }
        }
    } else if(i<arr1.length){
        if(Integer.parseInt(arr1[i]) != 0){
            return 1;
        }
    } else if(i<arr2.length){
       if(Integer.parseInt(arr2[i]) != 0){
            return -1;
        }
    }

    i++;
}

return 0;
}
  // Meant for when version numbers such as 2 and 2.0 arise. This method will make sure to
  // put the smaller version number ( in length) first
  public static int specialCompare(String str1, String str2)
 {
      String[] arr1 = str1.split("\\.");
     String[] arr2 = str2.split("\\.");
     for(int i =1; i<arr1.length;i++)
     {
        if(Integer.parseInt(arr1[i]) != 0)
        {
            return 0;
        }
    }
    for(int j =1; j<arr2.length;j++)
    {
        if(Integer.parseInt(arr2[j]) != 0)
        {
            return 0;
        }
    }
    if(arr1.length < arr2.length)
    {
        return -1;
    }
    else
    {
        return 1;
    }

}
}

4 个答案:

答案 0 :(得分:1)

我最近需要以更通用的方式为任意文件名执行此操作,类似于Windows资源管理器对文件进行排序的方式:

enter image description here

I wrote a blog post about thisThe idea was inspired by this answer here。用于以这种方式排序文件的比较器如下所示:

public final class FilenameComparator implements Comparator<String> {
    private static final Pattern NUMBERS = 
        Pattern.compile("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
    @Override public final int compare(String o1, String o2) {
        // Optional "NULLS LAST" semantics:
        if (o1 == null || o2 == null)
            return o1 == null ? o2 == null ? 0 : -1 : 1;

        // Splitting both input strings by the above patterns
        String[] split1 = NUMBERS.split(o1);
        String[] split2 = NUMBERS.split(o2);
        for (int i = 0; i < Math.min(split1.length, split2.length); i++) {
            char c1 = split1[i].charAt(0);
            char c2 = split2[i].charAt(0);
            int cmp = 0;

            // If both segments start with a digit, sort them numerically using 
            // BigInteger to stay safe
            if (c1 >= '0' && c1 <= '9' && c2 >= 0 && c2 <= '9')
                cmp = new BigInteger(split1[i]).compareTo(new BigInteger(split2[i]));

            // If we haven't sorted numerically before, or if numeric sorting yielded 
            // equality (e.g 007 and 7) then sort lexicographically
            if (cmp == 0)
                cmp = split1[i].compareTo(split2[i]);

            // Abort once some prefix has unequal ordering
            if (cmp != 0)
                return cmp;
        }

        // If we reach this, then both strings have equally ordered prefixes, but 
        // maybe one string is longer than the other (i.e. has more segments)
        return split1.length - split2.length;
    }
}

答案 1 :(得分:1)

我在Lukas Eder's blog post中阅读了comment above,并创建了一个java.util.Comparator,该import java.util.ArrayList; import java.util.List; public class JavaTest { public static void main(String[] args) { final List<String> chapters = new ArrayList<>(); chapters.add("1.1"); chapters.add("1.2"); chapters.add("1"); chapters.add("1.3"); chapters.add("1.1.1"); chapters.add("5.6"); chapters.add("1.1.10"); chapters.add("4"); chapters.add("1.1.9"); chapters.add("1.2.1.10"); chapters.add("2.1.1.4.5"); chapters.add("1.2.1.9"); chapters.add("1.2.1"); chapters.add("2.2.2"); chapters.add("1.2.1.11"); System.out.println("UNSORTED: " + chapters.toString()); chapters.sort(VersionNumberComparator.getInstance()); System.out.println("SORTED: " + chapters.toString()); } } 根据JDK proposal按版本(或章节)编号排序。

VersionNumberComparator是在GitHub要点中定义的。以下代码显示了它的工作原理。

UNSORTED: [1.1, 1.2, 1, 1.3, 1.1.1, 5.6, 1.1.10, 4, 1.1.9, 1.2.1.10, 2.1.1.4.5, 1.2.1.9, 1.2.1, 2.2.2, 1.2.1.11]
SORTED:   [1, 1.1, 1.1.1, 1.1.9, 1.1.10, 1.2, 1.2.1, 1.2.1.9, 1.2.1.10, 1.2.1.11, 1.3, 2.1.1.4.5, 2.2.2, 4, 5.6]

产生以下输出:

{{1}}

答案 2 :(得分:0)

来自specialCompare方法上方代码中的评论......

  

当出现2和2.0等版本号时。这种方法   将确保将较小的版本号(长度)放在第一位

所以我猜测你希望版本按版本号的长度排序。示例:从您提供的版本字符串数组中,您希望按以下排序...

0
2
0.0
0.1
1.2
1.113
2.0
0.0.0
1.1.1
1.2.1
2.0.0
0.0.0.1

如果是这种情况,那么你似乎正在使它变得更加复杂。当您获得版本长度不同的两个版本时,应该首先使用版本长度较短的版本。因此,简单检查版本拆分阵列的长度应该可以解决这个问题。如果长度相同,则需要检查每个版本。当版本长度相同时,不需要specialCompare方法。只需检查每个版本以及它们是否相同,然后转到下一个版本号,依此类推。只要一个版本不同,您就会知道要返回什么。如果您浏览整个阵列,那么您就知道所有版本号都是相同的。

以下是使用上述逻辑对compareVersion方法的更改。不需要specialCompare方法。我猜这就是你要找的东西。

public static int compareVersion(String version1, String version2)
{
  String[] arr1 = version1.split("\\.");
  String[] arr2 = version2.split("\\.");

  if (arr1.length < arr2.length)
     return -1;
  if (arr1.length > arr2.length)
     return 1;

  // same number of version "." dots
  for (int i = 0; i < arr1.length; i++)
  {
     if(Integer.parseInt(arr1[i]) < Integer.parseInt(arr2[i]))
       return -1;
     if(Integer.parseInt(arr1[i]) > Integer.parseInt(arr2[i]))
       return 1;
   }
   // went through all version numbers and they are all the same
   return 0;
}

答案 3 :(得分:0)

包com.e;

import java.util。*;

/ **  *由dpc于17-2-27创建。  *  * / 公共类VersionComparator实现Comparator {

@Override
public int compare(String o1, String o2) {

    if (o1 == null && o2 == null) {
        return 0;
    } else if (o1 == null && o2 != null) {
        return -1;
    } else if (o1 != null && o2 == null) {
        return 1;
    } else {
        if (o1.length() == 0 && o2.length() == 0) {
            return 0;
        } else if (o1.length() == 0 && o2.length() > 0) {
            return -1;
        } else if (o1.length() > 0 && o2.length() == 0) {
            return 1;
        } else {
            return compareVersion(o1, o2);
        }
    }


}


public static int compareVersion(String version1, String version2) {
    String[] arr1 = version1.split("\\.");
    String[] arr2 = version2.split("\\.");

    try {

        int i = 0;
        while (i < arr1.length || i < arr2.length) {
            if (i < arr1.length && i < arr2.length) {
                if (Integer.parseInt(arr1[i]) < Integer.parseInt(arr2[i])) {
                    return -1;
                } else if (Integer.parseInt(arr1[i]) > Integer.parseInt(arr2[i])) {
                    return 1;
                } else if (Integer.parseInt(arr1[i]) == Integer.parseInt(arr2[i])) {
                    int result = specialCompare(version1, version2);
                    if (result != 0) {
                        return result;
                    }
                }
            } else if (i < arr1.length) {
                if (Integer.parseInt(arr1[i]) != 0) {
                    return 1;
                }
            } else if (i < arr2.length) {
                if (Integer.parseInt(arr2[i]) != 0) {
                    return -1;
                }
            }

            i++;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return 0;
}

public static int specialCompare(String str1, String str2) {
    String[] arr1 = str1.split("\\.");
    String[] arr2 = str2.split("\\.");
    for (int i = 1; i < arr1.length; i++) {
        if (Integer.parseInt(arr1[i]) != 0) {
            return 0;
        }
    }
    for (int j = 1; j < arr2.length; j++) {
        if (Integer.parseInt(arr2[j]) != 0) {
            return 0;
        }
    }
    if (arr1.length < arr2.length) {
        return -1;
    } else {
        return 1;
    }
}


// test
public static List<String> getLowerList(String str, Comparator<String> comparator, List<String> list) {
    if (str == null) {
        return list;
    }
    List<String> newlist = new ArrayList<String>();
    newlist.add(str);
    newlist.addAll(list);
    // sort
    Collections.sort(newlist, comparator);
    // search
    int endIndex = Collections.binarySearch(newlist, str);
    if (endIndex >= 0) {
        // sublist 0 1
        return newlist.subList(0, endIndex + 1);
    } else {
        return new ArrayList<String>();
    }
}

public static void main(String[] args) {
    List<String> test1 = Arrays.asList(new String[]{
            "2.1.1", "1.21.22", "1.21.25", "1.113", "0.0.0.1",
            "2.0.0", "1.2", "2.0", "0.1", "1.2.1", "1.1.1",
            "11", "100", "" + Integer.MAX_VALUE + ".1", "",
            "2.0", "10.1"});

    List<String> test2 = Arrays.asList(new String[]{"", null, "0", "10.20.100", "3.1.1", "9.8", "10.3.92"});

    List<String> newlist = new ArrayList<String>();
    newlist.addAll(test1);
    newlist.addAll(test2);

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

    VersionComparator compareVersion = new VersionComparator();
    System.out.println(newlist);

    System.out.println(getLowerList("2", compareVersion, newlist));
    System.out.println(getLowerList("3", compareVersion, newlist));
    System.out.println(getLowerList("4", compareVersion, newlist));
    System.out.println(getLowerList("5", compareVersion, newlist));

}

}