集合排序意外行为

时间:2018-01-05 09:08:21

标签: java sorting

收藏品排序不是给我我期待的结果,还是我误读了这个方法?

要对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}]

3 个答案:

答案 0 :(得分:3)

  

我受到了冲突,所有具有line = true的对象都应该在   列表的开头,而不是结束。

不像这段代码:

  if (o1.isLine()) {
       return 1;
  } 

表示o1优于o2 因此,isLine=true的对象将在默认顺序升序时结束。

  

可以在列表的开头找到所有具有line = true的对象   现在,但他们已经换了位置(id = 0应该是第一个)。

你从不在比较器实现中使用id 它永远不会被考虑。

获得:

  

[Row {id = 0,line = true},Row {id = 2,line = true},Row {id = 1,line = false},   行{id = 3,line = false}]

您应该在Row中添加一个getter来检索id。 然后,您应该先按line=trueid 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排序且排序保证稳定:相等元素不会因排序而重新排序,因此您只能在{{ 1}}:

isLine

答案 1 :(得分:1)

总结@Dukeling:

    Collections.sort(rows, new Comparator<Row>(){
        @Override public int compare(Row o1, Row o2) {
            return -Boolean.compare(o1.isLine(), o2.isLine());
        }
    });

这给出了预期的结果。

输入:

[Row{id=0, line=true}, Row{id=1, line=false}, Row{id=2, line=true}, Row{id=3, line=false}]

结果:

[Row{id=0, line=true}, Row{id=2, line=true}, Row{id=1, line=false}, Row{id=3, line=false}]

答案 2 :(得分:0)

你的比较不是对称的,因此被打破了。使用 Boolean 类中实现的反向比较(请注意lambda body开头的 minus ):

>sudo yum install numactl-libs.x86_64
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * elrepo: mirrors.tuna.tsinghua.edu.cn
Package numactl-libs-2.0.9-6.el7_2.x86_64 already installed and latest version
Nothing to do