将比较器与多个比较器一起使用

时间:2018-08-06 11:37:06

标签: java arrays sorting compare comparator

我可以使用此代码中的所有简单比较器来排序,但不能排序ComplexComparator。我不知道如何编码才能使其正常工作。任何建议/解释将不胜感激。

这是我的主程序:

package pkgTest;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        Student[] students = new Student[6];
        students[0] = new Student("Pete", 1989, 3.6);
        students[1] = new Student("Tomas", 1989, 3.9);
        students[2] = new Student("Helen", 1990, 3.6);
        students[3] = new Student("Steve", 1991, 3.7);
        students[4] = new Student("Natalie", 1993, 3.7);
        students[5] = new Student("John", 1992, 4.0);

        NameComparator byName
                = new NameComparator();
        BirthDateComparator byBirthDate
                = new BirthDateComparator();
        AverageComparator byAverage
                = new AverageComparator();

        ComplexComparator complexSorting
                = new ComplexComparator(byName,
                        byAverage);

        System.out.println("===============");
        System.out.println("Before sorting:");
        System.out.println("===============");
        for (Student student : students) {
            System.out.println(student.getName()
                    + " // " + student.getBirthDate()
                    + " // " + student.getAverage());
        }

        Arrays.sort(students, complexSorting);

        System.out.println("==============");
        System.out.println("After sorting:");
        System.out.println("==============");
        for (Student student : students) {
            System.out.println(student.getName()
                    + " // " + student.getBirthDate()
                    + " // " + student.getAverage());
        }
    }
}

以下是其余的课程:

package pkgTest;

public class Student {

    private String name;
    private int birthDate;
    private double average;

    public Student(String name, int birthDate,
            double average) {
        this.name = name;
        this.birthDate = birthDate;
        this.average = average;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getBirthDate() {
        return this.birthDate;
    }

    public void setBirthDate(int birthDate) {
        this.birthDate = birthDate;
    }

    public double getAverage() {
        return this.average;
    }

    public void setAverage(double average) {
        this.average = average;
    }
}


package pkgTest;

import java.util.Comparator;

public class ComplexComparator implements Comparator<Student> {

    public ComplexComparator(Comparator<Student> one,
            Comparator<Student> another) {
    }

    @Override
    public int compare(Student one, Student another) {
        /*This is the part that
        I just couldn't figure
        it out to get it work.

        It has to work no matter
        which 2 of the 3 comparators
        I use to set the input
        parameters of ComplexComparator.

        I have to make it work by
        modifying only this part of
        the code.*/
    }
}


package pkgTest;

import java.util.Comparator;

public class AverageComparator implements Comparator<Student> {

    @Override
    public int compare(Student one, Student another) {
        if (one.getAverage()
                < another.getAverage()) {
            return -1;
        } else if (one.getAverage()
                == another.getAverage()) {
            return 0;
        } else {
            return +1;
        }
    }
}

package pkgTest;

import java.util.Comparator;

public class BirthDateComparator implements Comparator<Student> {

    @Override
    public int compare(Student one, Student another) {
        if (one.getBirthDate()
                < another.getBirthDate()) {
            return -1;
        } else if (one.getBirthDate()
                == another.getBirthDate()) {
            return 0;
        } else {
            return +1;
        }
    }
}


package pkgTest;

import java.util.Comparator;

public class NameComparator implements Comparator<Student> {

    @Override
    public int compare(Student one, Student another) {
        return one.getName().
                compareToIgnoreCase(another.getName());
    }
}

4 个答案:

答案 0 :(得分:2)

按如下所示修改您的ComplexComparator

public class ComplexComparator implements Comparator<Student> {

private List<Comparator<Student>> listComparators;

     @SafeVarargs
    public ComplexComparator(Comparator<Student>... comparators) {
        this.listComparators = Arrays.asList(comparators);
    }

    @Override
    public int compare(Student studen1, Student studen2) {
        for (Comparator<Student> comparator : listComparators) {
            int result = comparator.compare(studen1, studen2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}

答案 1 :(得分:2)

至少必须像下面那样修改类ComplexComparator,至少...

import java.util.Comparator;

public class ComplexComparator implements Comparator<Student> {

    private Comparator<Student> comparatorOne;
    private Comparator<Student> comparatorTwo;

    public ComplexComparator(Comparator<Student> one,
            Comparator<Student> another) {
        this.comparatorOne = one;
        this.comparatorTwo = another;
    }

    @Override
    public int compare(Student one, Student another) {
        // make a first comparison using comparator one
        int comparisonByOne = comparatorOne.compare(one, another);

        // check if it was 0 (items equal in that attribute)
        if (comparisonByOne == 0) {
            // if yes, return the result of the next comparison
            return comparatorTwo.compare(one, another);
        } else {
            // otherwise return the result of the first comparison
            return comparisonByOne;
        }
    }
}

对于两个以上的Comparator,您将需要其中的List个(或另一个重载的构造函数)和一个保持一定比较顺序的循环。

编辑

对于您对排序顺序的其他要求,这可能会有所帮助:

    public class ComplexComparator implements Comparator<Student> {

    private Comparator<Student> comparatorOne;
    private Comparator<Student> comparatorTwo;
    private boolean orderOneAscending = true;
    private boolean orderTwoAscending = true;

    /**
     * Constructor without any sort orders
     * @param one   a comparator
     * @param another   another comparator
     */
    public ComplexComparator(Comparator<Student> one, Comparator<Student> another) {
        this.comparatorOne = one;
        this.comparatorTwo = another;
    }

    /**
     * Constructor that provides the possibility of setting sort orders 
     * @param one   a comparator
     * @param orderOneAscending sort order for comparator one 
     *      (true = ascending, false = descending)
     * @param another   another comparator
     * @param orderTwoAscending sort order for comparator two
     *      (true = ascending, false = descending)
     */
    public ComplexComparator(Comparator<Student> one, boolean orderOneAscending,
            Comparator<Student> another, boolean orderTwoAscending) {
        this.comparatorOne = one;
        this.comparatorTwo = another;
        this.orderOneAscending = orderOneAscending;
        this.orderTwoAscending = orderTwoAscending;
    }

    @Override
    public int compare(Student one, Student another) {
        int comparisonByOne;
        int comparisonByAnother;

        if (orderOneAscending) {
            /*  note that your lexicographical comparison in NameComparator 
                returns a negative integer if the String is greater!
                If you take two numerical Comparators, the order will
                turn into the opposite direction! */
            comparisonByOne = comparatorOne.compare(another, one);
        } else {
            comparisonByOne = comparatorOne.compare(one, another);
        }

        if (orderTwoAscending) {
            comparisonByAnother = comparatorTwo.compare(one, another);
        } else {
            comparisonByAnother = comparatorTwo.compare(another, one);
        }

        if (comparisonByOne == 0) {
            return comparisonByAnother;
        } else {
            return comparisonByOne;
        }
    }
}

只需试一试这些值,然后尝试进行一些修改,以熟悉与比较和排序有关的常见问题。 我希望这会有所帮助...

答案 2 :(得分:0)

我不确定您要如何提出解决方案。但是据我了解,如果您只想将代码放在有注释的地方就可以这样做,则可以尝试将代码像这样放置。

假设比较名称后的情况(如果相同),您打算移动到平均值。

public int compare(Student StOne, Student StAnother) {
     if(one.compare(Sone, Sanother)==0) {
         return another.compare(StOne, StAnother);
         }
     else 
         return one.compare(StOne, StAnother);
     }

但是,为此,您需要确保在ComplexComparator的构造函数中使用的值(byName,byAverage)应该是该类的实例变量,并且需要在构造函数中进行初始化。

public class ComplexComparator implements Comparator<Student> {

 private Comparator<Student> one; 
 private Comparator<Student> another;
 public ComplexComparator(Comparator<Student> one,
        Comparator<Student> another) {
     this.one=one;
     this.another=another;
}

@Override
public int compare(Student one, Student another) {
    //code given above
} }

答案 3 :(得分:0)

这是一个通用的复杂比较器,可用于任何类型的对象(基于this answer):

public class ComplexComparator<T> implements Comparator<T> {

    private List<Comparator<T>> listComparators;

    @SafeVarargs
    public ComplexComparator(Comparator<T>... comparators) {
        listComparators = Arrays.asList(comparators);
    }

    @Override
    public int compare(T o1, T o2) {
        for (Comparator<T> comparator : listComparators) {
            int result = comparator.compare(o1, o2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}

使用时会出现未经检查的强制转换警告,但是只要您的班级具有可比性,它就可以成功转换,因此您可以取消它。

@SuppressWarnings("unchecked")
Comparator<MyClass> comparator = new ComplexComparator(
        MyClass.ComparatorA,
        MyClass.ComparatorB);

Collections.sort(mySet, comparator);

如果有人知道如何避免该警告,请发表评论,我会更新答案。