集合排序没有给我预期的结果,还是我误读了方法?
要排序的 Row 对象列表:
public class Row {
private int id;
private boolean line;
public Row(int id, boolean line) {
this.id = id;
this.line = line;
}
public boolean isLine() {
return line;
}
@Override public String toString() {
return "Row{" + "id=" + id + ", line=" + line + '}';
}
}
起始数据:
[Row{id=0, line=true}, Row{id=1, line=false}, Row{id=2, line=true}, Row{id=3, line=false}]
排序代码:
Collections.sort(rows, new Comparator<Row>(){
@Override public int compare(Row o1, Row o2) {
if (!o1.isLine() && !o2.isLine()) return 0;
if (o1.isLine()) {
return 1;
} else {
return -1;
}
}
});
结果:
[Row{id=1, line=false}, Row{id=3, line=false}, Row{id=0, line=true}, Row{id=2, line=true}]
我的印象是所有带有 line=true
的对象都应该在列表的开头,而不是结尾。
如果我稍微改变 Comporator 的实现:
Collections.sort(rows, new Comparator<Row>(){
@Override public int compare(Row o1, Row o2) {
if (!o1.isLine() && !o2.isLine()) return 0;
if (o1.isLine()) {
return -1;
} else {
return 1;
}
}
});
结果:
[Row{id=2, line=true}, Row{id=0, line=true}, Row{id=1, line=false}, Row{id=3, line=false}]
所有具有 line=true
的对象现在都可以在列表的开头找到,但它们已经交换了位置(id=0
应该是第一个)。
预期排序结果:
[Row{id=0, line=true}, Row{id=2, line=true}, Row{id=1, line=false}, Row{id=3, line=false}]
最佳答案
I was under the impresion that all objects with line=true should be at the start of the list, not the end.
不像这段代码:
if (o1.isLine()) {
return 1;
}
表示o1
优于o2
。
因此带有 isLine=true
的对象将发生在最后,因为默认顺序是升序。
All of objects with line=true can be found at the start of the list now, but they have switched places (id=0 should be first).
您永远不会在比较器实现中使用 id
。
绝对不能考虑。
得到:
[Row{id=0, line=true}, Row{id=2, line=true}, Row{id=1, line=false}, Row{id=3, line=false}]
您应该在 Row
中添加一个 getter 来检索 id
。
那么您应该首先按 line=true
和 id
ASC 排序。
Collections.sort(rows, new Comparator<Row>(){
@Override public int compare(Row o1, Row o2) {
if (!o1.isLine() && !o2.isLine()) return 0;
if (o1.isLine() && o2.isLine()) {
return o1.getId() > o2.getId();
}
if (o1.isLine()) {
return -1;
} else {
return 1;
}
}
});
一种更简洁的编写方式是使用 Java 8 Comparator:
Comparator<Row> comparatorRow = Comparator.comparing(Row::isLine).reversed()
.thenComparing(Row::getId);
由于行已经按 id
排序并且排序保证是稳定的:相同的元素不会因为排序而重新排序,您可以只比较在 isLine
上:
Comparator<Row> comparatorRow = Comparator.comparing(Row::isLine).reversed();
关于java - 集合排序意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48110333/