Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用多个字段排序,可以从优先级配置中添加/删除字段_Java_Sorting_Comparator_Priority Queue_Treemap - Fatal编程技术网

Java 使用多个字段排序,可以从优先级配置中添加/删除字段

Java 使用多个字段排序,可以从优先级配置中添加/删除字段,java,sorting,comparator,priority-queue,treemap,Java,Sorting,Comparator,Priority Queue,Treemap,我有一组数据,希望根据其字段和它们在给定配置中的优先级对这些数据进行排序 可以使用优先级队列或带有基于字段优先级的自定义比较器的树映射 我已经尝试过comparator方法,但它不够通用,无法处理优先级配置中对象字段的插入/删除 List<Students> students 1. Student1 : "agc", "2", "12 Aug 2001" 2. Student2 : "acc", "1", "12 Aug 2001" 3. Student3 : "abc", "2"

我有一组数据,希望根据其字段和它们在给定配置中的优先级对这些数据进行排序

可以使用优先级队列或带有基于字段优先级的自定义比较器的树映射

我已经尝试过comparator方法,但它不够通用,无法处理优先级配置中对象字段的插入/删除

List<Students> students

1. Student1 : "agc", "2", "12 Aug 2001"
2. Student2 : "acc", "1", "12 Aug 2001"
3. Student3 : "abc", "2", "12 Aug 2003"
studentsSorted=new PriorityQueue(学生,new CustomComparator())

studentsSorted=students.sort(Comparator.comparing(student::classRank)。然后比较(student::name))

答:排序顺序:

学生2 学生3 学生1

期望值:足够通用,可以在比较器中处理字段的插入/删除,而无需更改代码


请提供帮助。

为了满足您的期望,请编写一个自定义比较器,允许插入和删除要排序的字段。然后可以使用反射进行实际比较。你可以得到一些关于如何做到这一点的提示。请注意,在更改比较器后,您必须手动调用集合。

正如M.Prokhorov所评论的,您不应该使用更改行为的比较器实现PriorityQueue,因为这将导致其中断。事实上,如果任何类在其构造函数中使用比较器,那么该比较器必须是纯的——它的行为永远不能改变

尽管如此,这样一个比较器仍然有它的用途,这里有一种实现它的方法

class FieldComparator<T> implements Comparator<T> {

    private final List<Function<T, Comparable<?>>> functions = new ArrayList<>();

    public void add(Function<T, Comparable<?>> function) {
        functions.add(function);
    }

    @Override
    @SuppressWarnings("unchecked")
    public int compare(T t1, T t2) {
        for (Function<T, Comparable<?>> f : this) {
            Comparable c1 = f.apply(t1);
            Comparable c2 = f.apply(t2);
            int i = c1.compareTo(c2);
            if (i != 0) return i;
        }
        return 0;
    }
}

但我不建议将其用于PriorityQueue。

无论是
PriorityQueue
还是
TreeMap
都希望comparator在其生命周期内不会更改,否则它们将崩溃。当字段/优先级发生变化时,您需要构建一个新的比较器,克隆数据列表并使用新的比较器对其进行排序。在Java标准库中,无法在现有集合中执行此操作。如果您想这样做,您必须编写自己的集合。“如果任何类在其构造函数中采用了比较器,那么该比较器必须是纯的。”另外,请参见
FieldComparator
上的注释。它不应该从数组列表扩展,它应该使用数组列表并为它应该做的事情公开适当的API。这是一个很好的例子(关于继承滥用的注释)。@M.Prokhorov这正是我所说的。我的意思是比较器实例本身应该是纯的,也就是说,比较器的单个实例不应该能够改变它比较值的方式,相反,你应该把它换成不同的实例,这就是我所说的纯。另外,是的,关于组合而不是继承,你是对的,这只是我的懒惰:)。
class FieldComparator<T> implements Comparator<T> {

    private final List<Function<T, Comparable<?>>> functions = new ArrayList<>();

    public void add(Function<T, Comparable<?>> function) {
        functions.add(function);
    }

    @Override
    @SuppressWarnings("unchecked")
    public int compare(T t1, T t2) {
        for (Function<T, Comparable<?>> f : this) {
            Comparable c1 = f.apply(t1);
            Comparable c2 = f.apply(t2);
            int i = c1.compareTo(c2);
            if (i != 0) return i;
        }
        return 0;
    }
}
public static void main(String[] args) {
    FieldComparator<Student> comparator = new FieldComparator<>();
    comparator.add(Student::getClassRank);
    comparator.add(Student::getName);

    List<Student> students = Arrays.asList(
            new Student("Mark", 2),
            new Student("John", 1),
            new Student("Andy", 2),
            new Student("Uche", 1),
            new Student("Luke", 2),
            new Student("Mary", 1),
            new Student("Lucy", 2)
    );
    students.sort(comparator);
    System.out.println(students);
}
[Student{John, 1}, Student{Mary, 1}, Student{Uche, 1}, 
 Student{Andy, 2}, Student{Lucy, 2}, Student{Luke, 2}, Student{Mark, 2}]