简体   繁体   English

如何在 Java 中按字母顺序对枚举成员进行排序?

[英]How do I sort enum members alphabetically in Java?

I have an enum class like the following:我有一个枚举类,如下所示:

public enum Letter {
    OMEGA_LETTER("Omega"), 
    GAMMA_LETTER("Gamma"), 
    BETA_LETTER("Beta"), 
    ALPHA_LETTER("Alpha"), 

    private final String description;

    Letter() {
      description = toString();
    }

    Letter(String description) {
      this.description = description;
    }

    public String getDescription() {
      return description;
    }
}

Later down my code I basically iterate over the Letter enum and print its members out to the console:后来在我的代码中,我基本上遍历 Letter 枚举并将其成员打印到控制台:

for (Letter letter : Letter.values()) {
System.out.println(letter.getDescription());
}

I thought that the values() method would give me an ordered view of the enum (as mentioned here ), but this is not the case here.我认为值()方法会给我的枚举的有序视图(如提到这里),但这里不是这种情况。 I simply get the enum members in the order I created them within the Letter enum class.我只是按照我在 Letter 枚举类中创建它们的顺序获取枚举成员。 Is there a way to output the values of an enum in alphabetical order?有没有办法按字母顺序输出枚举的值? Would I need a separate comparator object, or is there a built-in way to do this?我需要一个单独的比较器对象,还是有内置的方法来做到这一点? Basically I would like the values to be alphabetically sorted based on the getDescription() text:基本上,我希望根据 getDescription() 文本按字母顺序对值进行排序:

Alpha
Beta
Gamma
Omega
SortedMap<String, Letter> map = new TreeMap<String, Letter>();
for (Letter l : Letter.values()) {
    map.put(l.getDescription, l);
}
return map.values();

Or just reorder the declarations :-)或者只是重新排序声明:-)

Edit: As KLE pointed out, this assumes that the Descriptions are unique within the enum.编辑:正如 KLE 所指出的,这假设描述在枚举中是唯一的。

I thought that the values() method would give me an ordered view of the enum (as mentioned here), but this is not the case here.我认为 values() 方法会给我一个枚举的有序视图(如此处提到的),但这里的情况并非如此。 I simply get the enum members in the order I created them within the Letter enum class.我只是按照我在 Letter 枚举类中创建它们的顺序获取枚举成员。

Precisely, the order of declaration is considered significant for enums, so we are glad that they are returned in precisely that order.确切地说,声明的顺序对于枚举来说很重要,所以我们很高兴它们是按照这个顺序返回的。 For example, when a int i represents an enum values, doing values()[i] is a very simple and efficient way to find the enum instance.例如,当int i表示枚举值时,执行values()[i]是一种非常简单有效的查找枚举实例的方法。 To go contrary-wise, the ordinal() method returns the index of an enum instance.相反, ordinal()方法返回枚举实例的索引。

Is there a way to output the values of an enum in alphabetical order?有没有办法按字母顺序输出枚举的值? Would I need a separate comparator object, or is there a built-in way to do this?我需要一个单独的比较器对象,还是有内置的方法来做到这一点? Basically I would like the values to be alphabetically sorted based on the getDescription() text:基本上,我希望根据 getDescription() 文本按字母顺序对值进行排序:

What you call value is not something defined for enums in general.您所说的通常不是为枚举定义的。 Here, in your context, you mean the result of getDescription() .在这里,在您的上下文中,您的意思是getDescription()的结果。

As you say, you could create a Comparator for these descriptions .正如您所说,您可以为这些描述创建一个 Comparator That would be perfect :-)那将是完美的:-)


Note that in general, you could need several orders for these instances :请注意,通常,您可能需要为这些实例提供多个订单

  • declaration order (this is the official order)声明令(这是官方命令)
  • description order描述顺序
  • others as needed其他人根据需要

You could also push that notion of DescriptionComparator a little bit:你也可以稍微推动一下 DescriptionComparator 的概念:

  1. For performance reasons, you could store the computed descriptions.出于性能原因,您可以存储计算出的描述。

  2. Because enums can't inherit, code reuse has to be outside the enum class.因为枚举不能继承,代码重用必须在枚举类之外。 Let me give the example we would use in our projects:让我举一个我们将在我们的项目中使用的例子:

Now the code samples...现在代码示例...

/** Interface for enums that have a description. */
public interface Described {
  /** Returns the description. */
  String getDescription();
}

public enum Letter implements Described {
  // .... implementation as in the original post, 
  // as the method is already implemented
}

public enum Other implements Described {
  // .... same
}

/** Utilities for enums. */
public abstract class EnumUtils {

  /** Reusable Comparator instance for Described objects. */
  public static Comparator<Described> DESCRIPTION_COMPARATOR = 
    new Comparator<Described>() {
      public int compareTo(Described a, Described b) {
        return a.getDescription().compareTo(b.getDescription);
      }
    };

  /** Return the sorted descriptions for the enum. */
  public static <E extends Enum & Described> List<String> 
    getSortedDescriptions(Class<E> enumClass) {
      List<String> descriptions = new ArrayList<String>();
      for(E e : enumClass.getEnumConstants()) {
        result.add(e.getDescription());
      }
      Collections.sort(descriptions);
      return descriptions;
  }
}

// caller code
List<String> letters = EnumUtils.getSortedDescriptions(Letter.class);
List<String> others = EnumUtils.getSortedDescriptions(Other.class);

Note that the generic code in EnumUtils works not only for one enum class, but works for any enum class in your project that implements the Described interface .请注意, EnumUtils中的通用代码不仅适用于一个枚举类,还适用于项目中实现了Described interface 的任何枚举类

As said before, the point of having the code outside of the enums (where it would otherwise belong) is to reuse the code.如前所述,将代码放在枚举之外(否则将属于它的地方)的重点是重用代码。 It's not big deal for two enums, but we have over a thousand enums in our project, many of them with the same interfaces...!两个枚举没什么大不了的,但是我们的项目中有超过一千个枚举,其中许多具有相同的接口......!

只需使用 Arrays.sort 和您自己的比较器对它们进行排序。

Here's a generic way to do it with any class without having to implement Comparable on the class you're sorting or create a custom comparator.这是对任何类执行此操作的通用方法,而无需在您正在排序的类上实现 Comparable 或创建自定义比较器。 I've found instances where I don't want to override compareTo because it serves a different purpose, you can't for enums anyways, and constantly creating wrapper classes is a pain.我发现我不想覆盖 compareTo 的实例,因为它用于不同的目的,无论如何你不能用于枚举,并且不断创建包装类是一种痛苦。 You can pass in a function that outputs a Comparable object you'd like to use for sorting purposes.您可以传入一个函数,该函数输出您想用于排序目的的 Comparable 对象。

The toComparable function is only called once per element in the list (not so for a custom comparator), so it's especially good if that call is expensive for some class. toComparable 函数仅对列表中的每个元素调用一次(对于自定义比较器而言并非如此),因此如果该调用对于某些类来说很昂贵,则特别好。 Null values are handled internally, so it's easier to use than a custom comparator.空值在内部处理,因此它比自定义比较器更易于使用。 One call to Java 7's TimSort algorithm is drastically more efficient than doing a bunch of O(log N) inserts to a SortedMap (red-black tree or other balanced tree implementation).一次调用 Java 7 的 TimSort 算法比对 SortedMap(红黑树或其他平衡树实现)执行一堆 O(log N) 插入要高效得多。 And you aren't restricted to any particular class or interface.而且您不受任何特定类或接口的限制。

Real world performance increases are significant in many cases.在许多情况下,现实世界的性能提升是显着的。 For example, the performance increase is around 5x as fast as using a comparator when sorting Doubles using toString() on a list of size 100k.例如,在大小为 100k 的列表上使用 toString() 对 Doubles 进行排序时,性能提升大约是使用比较器的 5 倍。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;

public class GenericLetterSorter {
    public enum Letter {
        OMEGA_LETTER("Omega"), 
        GAMMA_LETTER("Gamma"), 
        BETA_LETTER("Beta"), 
        ALPHA_LETTER("Alpha"); 

        private final String description;

        Letter() {
          description = toString();
        }

        Letter(String description) {
          this.description = description;
        }

        public String getDescription() {
          return description;
        }
    }

public static void main(String[] args) {
    List<Letter> list = new ArrayList<>(Arrays.asList(Letter.values()));

    sort(list, new ToComparable<Letter>() {
        @Override
        public Comparable toComparable(Letter letter) {
            // sort based on the letter's description
            return letter == null ? null : letter.getDescription();
        }
    });

    for (Letter letter : list)
        System.out.println(letter == null ? null : letter.name());
}

    public interface ToComparable<T, C extends Comparable<? super C>> {
         C toComparable(T t);
    }

    public static <T, C extends Comparable<? super C>> void sort(List<T> list, ToComparable<T, C> function) {
       class Pair implements Comparable<Pair> {
          final T original;
          final C comparable;

          Pair(T original, C comparable) {
             this.original = original;
             this.comparable = comparable;
          }

          @Override
          public int compareTo(Pair other) {
                return
                  comparable == null && other.comparable == null ? 0 :
                  comparable == null ? -1 :
                  other.comparable == null ? 1 :
                  comparable.compareTo(other.comparable);
          }
       }

       List<Pair> pairs = new ArrayList<>(list.size());
       for (T original : list)
          pairs.add(new Pair(original, function.toComparable(original)));

       Collections.sort(pairs);

       ListIterator<T> iter = list.listIterator();
       for (Pair pair : pairs) {
          iter.next();
          iter.set(pair.original);
       }
    }
}

You can use sorted function with comparator in java8您可以在java8中使用带有比较器的排序函数

enumlist.stream()
.sorted(Comparator.comparing(Enum::toString)).collect(Collectors.toList());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM