基于枚举的排序具有随机行为

时间:2017-07-14 12:05:12

标签: java sorting enums comparable

对于下面的代码,我试图根据枚举类型对bean进行排序。对于这个bean,枚举类型也可以为null。

排序后的序列应为:

A -> B -> C -> null.

在代码下面运行后,元素的排序方式如下:

[A, A, C, B, B, null, C, null]

请帮忙

public class Bean implements Comparable<Bean> {

    enum Type {
      A, B, C
    }

    private Type type;
    private int i;
    private int j;

    public Bean(Type type, int i, int j) {
      this.type = type;
      this.i = i;
      this.j = j;
    }

    @Override
    public int compareTo(Bean that) {
       if (this.type == that.type) {
         return 0;
       }
       if (this.type != null && that.type != null) {
         if (this.type == type.A &&
            that.type == type.B) {
          return -1;
        }
        if (this.type == type.B &&
            that.type == type.C) {
          return -1;
        }
        if (this.type == type.A &&
            that.type == type.C) {
          return -1;
        }
        return 1;
      }

      return this.type == null ? 1 : -1;
    }

    @Override
    public String toString() {
      return "Bean{" + "type=" + (type != null ? type : "Unknown") + "}";
    }

    public static void main(String[] args) {
      Bean b1 = new Bean(Type.B, 1, 1);
      Bean b3 = new Bean(null, 3, 3);
      Bean b2 = new Bean(Type.C, 2, 2);
      Bean b0 = new Bean(Type.A, 0, 0);
      Bean b4 = new Bean(Type.B, 4, 4);
      Bean b5 = new Bean(null, 5, 5);
      Bean b6 = new Bean(Type.C, 6, 6);
      Bean b7 = new Bean(Type.A, 7, 7);

      List<Bean> list = new ArrayList<>();
      list.add(b1);
      list.add(b3);
      list.add(b2);
      list.add(b0);
      list.add(b4);
      list.add(b5);
      list.add(b6);
      list.add(b7);

      System.out.println(list);

      System.out.println(new PriorityQueue<Bean>(list));
    }
}

3 个答案:

答案 0 :(得分:3)

相反,你应该做的是让你自己的脖子无效的枚举:

enum Type {
    A, B, C, INVALID
}

然后

public Bean(Type type, int i, int j) {
    this.type = type == null ? Type.INVALID : type;
    this.i = i;
    this.j = j;
}

和比较器将如此简单易读:

@Override
public int compareTo(Bean that) {
    return this.type.compareTo(that.type);
}

请注意,因为Enum<E>通过枚举的自然顺序实现Comparable<E>,所以可以这样做

这样做

System.out.println(list);
Collections.sort(list);
System.out.println(list);

将产生:

[Bean{type=B}, Bean{type=INVALID}, Bean{type=C}, Bean{type=A}, Bean{type=B}, Bean{type=INVALID}, Bean{type=C}, Bean{type=A}]
[Bean{type=A}, Bean{type=A}, Bean{type=B}, Bean{type=B}, Bean{type=C}, Bean{type=C}, Bean{type=INVALID}, Bean{type=INVALID}]

答案 1 :(得分:2)

我发现CompareTo没有特别的问题,除了随着枚举量的增加而缩小其复杂程度 问题出在不同的地方:priorityQueue.toString不会从队列中提取项目,它只是打印基础二进制堆结构。

请注意,二进制堆只是部分排序。它确保a [i]> a [2 * i]和[2 * i + 1],关于[2 * i]和[2 * i + 1]的排序,事先无法提及。< / p>

这个问题已经出现在stackoverflow中: PriorityQueue.toString wrong element order

答案 2 :(得分:0)

您未考虑this.typethat.type的所有可能组合。你忘了:

  • if (this.type == Type.B && that.type == Type.A)
  • if (this.type == Type.C && that.type == Type.A)
  • if (this.type == Type.C && that.type == Type.B)

然而,有一种更简单的方法。所有枚举常量都是可比较的。它们的自然顺序是它们在源中声明的顺序。所以你可以这样做:

if (this.type != null && that.type != null) {
    return this.type.compareTo(that.type);
}