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

Using comparator with multiple comparators

我可以使用这段代码中的所有简单比较器进行排序,但 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());
    }
}

如下修改您的 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;
    }
}

我不确定您希望如何呈现解决方案。但是根据我的理解,如果你想通过将代码放在注释的地方来做到这一点,你可以尝试像这样放置代码。

假设比较名字后的情况,如果相同,你打算移动到平均。

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)的构造函数中取的值应该是class的实例变量,并且需要在构造函数中进行初始化。

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

您必须像下面这样修改 class 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;
        }
    }
}

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

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

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;
    }
}

当你使用它时会有一个未经检查的投射警告,但你可以抑制它,因为只要你的 class 相当它就会投射成功。

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

Collections.sort(mySet, comparator);

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