使用可比较的排序

时间:2014-02-25 22:44:21

标签: java sorting comparable

简介

我使用Comparable进行自定义排序的代码并不像我想要的那样工作。我基本上采用一系列目录并按以下方式对它们进行排序:

  1. 第一个目录,第一个目录越少。
  2. 如果按字母顺序排列。
  3. 问题

    您输入的示例:

      

    [“/”,“/ usr /”,“/ usr / local /”,“/ usr / local / bin /”,“/ games /”,   “/ games / snake /”,“/ homework /”,“/ temp / downloads /”]

    哪个应该归还:

      

    [“/”,“/ games /”,“/ homework /”,“/ usr /”,“/ games / snake /”,   “/ temp / downloads /”,“/ usr / local /”,“/ usr / local / bin /”]

    但由于某些原因,我的代码会返回:

      

    [“/”,“/ usr /”,“/ games /”,“/ homework /”,“/ usr / local /”,   “/ games / snake /”,“/ usr / local / bin /”,“/ temp / downloads /”]

    我的代码 [已修改评论]

    import java.util.*;
    
    public class Dirsort { public String[] sort(String[] dirs) {
        //Creates Array list containing Sort object
        ArrayList<Sort> mySort = new ArrayList<Sort>();
        //Loop that gets the 3 needed values for sorting
            for (String d: dirs){
                String [] l = d.split("/");//String array for alphabetical comparison
                int di = d.length();//Length of array for sorting by number of directories
                mySort.add(new Sort(di,l,d));//adds Sort object to arraylist (note d (the entire directory) is needed for the toString)
            }
            Collections.sort(mySort);//sorts according to compareTo
            String [] ans = new String [mySort.size()];//Creates a new string array that will be returned
            int count = 0;//to keep track of where we are in the loop for appending
            for (Sort s: mySort){
                ans[count] = s.toString();
                count++;
            }
            return ans;
        }
        class Sort implements Comparable<Sort>{
            private int d;//number of directories
            private String [] arr;//array of strings of names of directories
            private String dir;//full directory as string for toString
    
            //Constructor
            public Sort(int myD, String [] myArr, String myDir){
                d = myD;
                arr = myArr;
                dir = myDir;
            }
    
            //toString
            public String toString(){
                return dir;
            }
    
            @Override
            public int compareTo(Sort arg0) {
                // TODO Auto-generated method stub
                //If they are the same return 0
                if (this.equals(arg0)){
                    return 0;
                }
    
                //if the directories are empty
                if("/".equals(arg0.dir)){
                    return 1;
                }
                if ("/".equals(this.dir)){
                    return -1;
                }
    
                //If they are not the same length the shorter one comes first
                if (this.d != arg0.d){
                    return this.d - arg0.d;
                }
    
                //If they are the same length, compare them alphabetically
                else{
                    for (int i = 0; i < arg0.d; i++){
                        if (!this.arr[i].equals(arg0.arr[i])){
                            return this.arr[i].compareTo(arg0.arr[i]);
                        }
                    }
                }
                return 0;
            }   
        }
    }
    

3 个答案:

答案 0 :(得分:1)

错误在这里:

for (String d: dirs){
    String [] l = d.split("/");

    int di = d.length(); // <- here

    mySort.add(new Sort(di,l,d));
}

因为您要比较整个目录String的长度,而不是目录中“文件夹”的数量。这就是为什么"/usr/"出现在"/homework/"之前,例如,因为:

"/usr/".length() == 5
"/homework/".length() == 10

我相信你想要的是这个,使用分割的长度:

int di = l.length;

然后输出是:

/
/games/
/homework/
/usr/
/games/snake/
/temp/downloads/
/usr/local/
/usr/local/bin/

虽然(可能)还有另一个小错误,就是在以分隔符开头的String上调用split会在开头导致一个空字符串。

IE:

"/usr/".split("/") == { "", "usr" }

所以你可能想要做些什么。虽然这里意味着所有这些都以空字符串开头,所以它不会对你进行比较的方式产生影响。

作为旁注,@ JBNizet建议给你的变量更有意义的名字也有帮助。 fullDir.length()splitDir.length会更容易发现(并且可能从未发生过这种情况)。

答案 1 :(得分:0)

这是你的代码的固定版本,它处理两个目录都是"/"的情况,它删除了部分数组不必要的,错误传递的长度,并使用了更有意义的变量名:

public class Dirsort {

    public static void main(String[] args) {
        String[] input = new String[] {
            "/", 
            "/usr/", 
            "/usr/local/", 
            "/usr/local/bin/", 
            "/games/", 
            "/games/snake/", 
            "/homework/", 
            "/temp/downloads/"
        };
        String[] result = new Dirsort().sort(input);
        System.out.println("result = " + Arrays.toString(result));
    }

    public String[] sort(String[] dirs) {
        ArrayList<Sort> sorts = new ArrayList<Sort>();
        for (String dir : dirs) {
            String[] parts = dir.split("/");
            sorts.add(new Sort(parts, dir));
        }
        Collections.sort(sorts);
        String[] result = new String[sorts.size()];
        int count = 0;
        for (Sort sort: sorts) {
            result[count] = sort.toString();
            count++;
        }
        return result;
    }

    class Sort implements Comparable<Sort> {
        private String[] parts;
        private String dir;

        public Sort(String[] parts, String dir) {
            this.parts = parts;
            this.dir = dir;
        }

        public String toString(){
            return dir;
        }

        @Override
        public int compareTo(Sort other) {
            if (this.equals(other)){
                return 0;
            }
            if("/".equals(other.dir) && "/".equals(dir)) {
                return 0;
            }
            if("/".equals(other.dir)){
                return 1;
            }
            if ("/".equals(this.dir)){
                return -1;
            }

            if (this.parts.length != other.parts.length){
                return this.parts.length - other.parts.length;
            }
            else {
                for (int i = 0; i < other.parts.length; i++){
                    if (!this.parts[i].equals(other.parts[i])){
                        return this.parts[i].compareTo(other.parts[i]);
                    }
                }
            }
            return 0;
        }   
    }
}

我通过简单地使用我的调试器并使其显示所有变量的值来发现问题。

答案 2 :(得分:0)

public class Disort
{
    public static String[] sort(String[] dirs)
    {
        ArrayList<Path> mySort = new ArrayList<Path>();

        Path pathDir;
        for(String dir : dirs){
            pathDir = Paths.get(dir);
            // check if directory exists
            if(Files.isDirectory(pathDir)){
                mySort.add(pathDir);
            }
        }

        // sort the ArrayList according a personalized comparator
        Collections.sort(mySort, new Comparator<Path>(){

            @Override
            public int compare(Path o1, Path o2)
            {
                if(o1.getNameCount() < o2.getNameCount()){
                    return -1;
                }
                else if(o1.getNameCount() > o2.getNameCount()){
                    return 1;
                }
                else{
                    return o1.compareTo(o2);
                }
            }

        });

        // to return a String[] but it will better to return a ArrayList<Path>
        String[] result = new String[mySort.size()];
        for(int i = 0; i < result.length; i++){
            result[i] = mySort.get(i).toString();
        }

        return result;
    }
}