如何在 Java 中按字母顺序对枚举成员进行排序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1734872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I sort enum members alphabetically in Java?
提问by denchr
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. 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:
我认为值()方法会给我的枚举的有序视图(如提到这里),但这里不是这种情况。我只是按照我在 Letter 枚举类中创建它们的顺序获取枚举成员。有没有办法按字母顺序输出枚举的值?我需要一个单独的比较器对象,还是有内置的方法来做到这一点?基本上,我希望根据 getDescription() 文本按字母顺序对值进行排序:
Alpha
Beta
Gamma
Omega
采纳答案by meriton
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 所指出的,这假设描述在枚举中是唯一的。
回答by Dmitry
Just sort them using Arrays.sort and your own comparator.
只需使用 Arrays.sort 和您自己的比较器对它们进行排序。
回答by 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. I simply get the enum members in the order I created them within the Letter enum class.
我认为 values() 方法会给我一个枚举的有序视图(如此处提到的),但这里的情况并非如此。我只是按照我在 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. To go contrary-wise, the ordinal()
method returns the index of an enum instance.
确切地说,声明的顺序对于枚举来说很重要,所以我们很高兴它们是按照这个顺序返回的。例如,当 aint i
代表一个枚举值时,doingvalues()[i]
是一种非常简单有效的查找枚举实例的方法。相反,该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 valueis 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. That would be perfect :-)
正如您所说,您可以为这些描述创建一个 Comparator。那将是完美的:-)
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 的概念:
For performance reasons, you could store the computed descriptions.
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...!
如前所述,将代码放在枚举之外(否则它应该属于它的地方)的重点是重用代码。两个枚举没什么大不了的,但是我们的项目中有超过一千个枚举,其中许多具有相同的接口......!
回答by pscuderi
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. 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. You can pass in a function that outputs a Comparable object you'd like to use for sorting purposes.
这是对任何类执行此操作的通用方法,而无需在您正在排序的类上实现 Comparable 或创建自定义比较器。我发现我不想覆盖 compareTo 的实例,因为它用于不同的目的,无论如何你不能用于枚举,并且不断创建包装类是一种痛苦。您可以传入一个函数,该函数输出您想用于排序目的的 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. 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). And you aren't restricted to any particular class or interface.
toComparable 函数仅对列表中的每个元素调用一次(对于自定义比较器而言并非如此),因此如果该调用对于某些类来说很昂贵,则特别好。空值在内部处理,因此它比自定义比较器更易于使用。对 Java 7 的 TimSort 算法的一次调用比对 SortedMap(红黑树或其他平衡树实现)执行一堆 O(log N) 插入要高效得多。而且您不受任何特定类或接口的限制。
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);
}
}
}