【问题标题】:Sorting: How to create a particular custom order, then alphabetic sort in java排序:如何创建特定的自定义顺序,然后在 java 中按字母排序
【发布时间】:2013-02-12 01:24:01
【问题描述】:

我有一个包含大约 70 个字段的枚举。

我希望其中 10 个按特定顺序显示,然后我希望其余的使用比较器按字母顺序显示。我已经尝试了很多东西,但我无法让它发挥作用。

这是一个带有 reduce 属性的示例枚举 我希望首先显示 Picard、Worf 和 William,然后按字母顺序显示其余部分

我不能使用任何第三个库。它必须是java核心。因此,如果您想提供 guava 答案,或者 apache commons 答案,请在 java core 之外提供。

public enum StarTrek {

    JeanLucPicard("Picard"),
    GeordiLaForge("Geordi"),
    DiannaTroi("Dianna"),
    Worf("Worf"),
    WilliamRiker("William"),
    Q("Q");

    private String label;

    StarTrek(String label) { this.label = label; }

    @Override public String toString() { return label; }
}

    List<StarTrek> specificOrder = Arrays.asList(StarTrek.JeanLucPicard, StarTrek.Worf, StarTrek.WilliamRiker);

    Comparator<StarTrek> comp = new Comparator<StarTrek>() {
            @Override
            public int compare(StarTrek o1, StarTrek o2) {
                //TODO: loop through the specific order, and display those first, then for the rest, go alphabetic
                return 0;
            }
    };

    List<StarTrek> all = Arrays.asList(StarTrek.values());
    Collections.sort(all, comp);

【问题讨论】:

  • 为什么不分两步做呢?
  • 我已经通过不使用排序来解决它,只是在集合中删除和添加,但我想使用排序来解决它。它好多了。我也只想调用一次排序
  • 我不太确定它是否更好。两个步骤对我来说更具可读性,并阻止您使用仅用于显示的元数据污染您的枚举类。
  • 在这种情况下,请按照其他人的建议进行操作。

标签: java list sorting collections comparator


【解决方案1】:

仅出于按特定顺序显示的目的而在枚举中放置其他数据是不好的设计。相反,将所有这些逻辑放在您的 Comparator 中,如下所示:

public class StarTrekSorter implements Comparator<StarTrek> {

  private static final List<StarTrek> ORDERED_ENTRIES = Arrays.asList(
      StarTrek.JeanLucPicard, StarTrek.Worf, StarTrek.WilliamRiker);

  @Override
  public int compare(StarTrek o1, StarTrek o2) {
    if (ORDERED_ENTRIES.contains(o1) && ORDERED_ENTRIES.contains(o2)) {
      // Both objects are in our ordered list. Compare them by
      // their position in the list
      return ORDERED_ENTRIES.indexOf(o1) - ORDERED_ENTRIES.indexOf(o2);
    }

    if (ORDERED_ENTRIES.contains(o1)) {
      // o1 is in the ordered list, but o2 isn't. o1 is smaller (i.e. first)
      return -1;
    }

    if (ORDERED_ENTRIES.contains(o2)) {
      // o2 is in the ordered list, but o1 isn't. o2 is smaller (i.e. first)
      return 1;
    }

    return o1.toString().compareTo(o2.toString());
  }
}

现在,你可以排序了:

public static void main(String[] args) {

  List<StarTrek> cast = Arrays.asList(StarTrek.values());

  Collections.sort(cast, new StarTrekSorter());

  for (StarTrek trek : cast) {
    System.out.println(trek);
  }  
}

打印出来的

Picard
Worf
William
Dianna
Geordi
Q

【讨论】:

  • 您能逐步解释一下这是怎么回事吗?这个比较器很难理解
  • @Shervin 我添加了一些 cmets 来尝试帮助。 compare 方法总是让人难以理解。
  • @DuncanJones 谢谢。它有帮助。不过还是觉得很难:)
  • @Shervin 我发现很难写! compare 的 Javadocs 不是最容易阅读的。有时,最简单的方法是只用一小组值进行试验,以确保排序符合您的预期。
  • 非常感谢您花时间为我做这件事!
【解决方案2】:

我会这样做:

JeanLucPicard("Picard", 0),
GeordiLaForge("Geordi"),
DiannaTroi("Dianna"),
Worf("Worf", 1),
WilliamRiker("William", 2),
Q("Q");

StarTrek(String label) { this(label, -1); }
StarTrek(String label, int orderHint) { this.label=label; this.orderHint=orderHint; }

compare 方法中是这样的:

if (orderHint == -1) {
   return o1.label.compareTo(o2.label));
}
return o2.orderHint-o1.orderHint;

【讨论】:

  • 除了改变我的枚举实现,没有别的办法了吗?
【解决方案3】:

首先在列表中列出您想要特殊排序的枚举,然后使用以下代码:

Comparator<StarTrek> comp = new Comparator<StarTrek>() {
    public int compare(StarTrek o1, StarTrek o2) {
        if (o1.ordinal() < 3)
            return o2.ordinal() < 3 ? o1.ordinal() - o2.ordinal() : 1;
        return o2.ordinal() < 3 ? -1 : o1.name().compareTo(o2.name());
    }
};

【讨论】:

    【解决方案4】:

    你可以在你的枚举中定义一个额外的构造函数,它接受一个索引参数,然后为你想先去的实例提供索引(让你想去的那些不按字母顺序排列):

    enum StarTrek {
    
        JeanLucPicard("Picard"),
        GeordiLaForge("Geordi"),
        DiannaTroi("Dianna"),
        Worf("Worf", 2),
        WilliamRiker("William", 1),
        Q("Q");
    
        private final String label;
        private final Integer index;
    
        StarTrek(final String label, final Integer index ) { this.label = label; this.index = index; }
    
        StarTrek(final String label) { this.label = label; this.index = Integer.MAX_VALUE; }
    
        @Override public String toString() { return label; }
    
        public Integer getIndex() {
            return index;
        }
    }
    

    那么你的比较器必须看起来像:

    final Comparator<StarTrek> comp = new Comparator<StarTrek>() {
                    @Override
                    public int compare(final StarTrek o1, final StarTrek o2) {
                        if (!o1.getIndex().equals(o2.getIndex())) {
                            return o1.getIndex().compareTo(o2.getIndex());
                        }
                        return o1.toString().compareTo(o2.toString());
                    }
            };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      • 2012-11-02
      • 2017-11-17
      • 1970-01-01
      • 2020-09-03
      • 1970-01-01
      相关资源
      最近更新 更多