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

发布于 2024-08-10 20:00:23 字数 1059 浏览 8 评论 0原文

我有一个如下所示的枚举类:

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;
    }
}

稍后在我的代码中,我基本上迭代 Letter 枚举并将其成员打印到控制台:

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

我认为 values() 方法会给我一个枚举的有序视图(如此处所述) ,但事实并非如此。我只是按照我在 Letter 枚举类中创建枚举成员的顺序获取枚举成员。

有没有办法按字母顺序输出枚举的值?我是否需要一个单独的 Comparator 对象,或者是否有内置方法可以做到这一点?基本上我希望根据 getDescription() 文本按字母顺序对值进行排序:

Alpha
Beta
Gamma
Omega

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 in my code, I basically iterate over the Letter enum and print its members out to the console:

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. 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:

Alpha
Beta
Gamma
Omega

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

初见 2024-08-17 20:00:23
SortedMap<String, Letter> map = new TreeMap<String, Letter>();
for (Letter l : Letter.values()) {
    map.put(l.getDescription, l);
}
return map.values();

或者只是重新排序声明:-)

编辑:正如 KLE 指出的,这假设描述在枚举中是唯一的。

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.

情何以堪。 2024-08-17 20:00:23

我认为values()方法会给我一个枚举的有序视图(如此处提到的),但这里的情况并非如此。我只是按照我在 Letter 枚举类中创建枚举成员的顺序获取枚举成员。

准确地说,声明的顺序对于枚举来说很重要,因此我们很高兴它们完全按照该顺序返回。例如,当 int i 表示枚举值时,执行 values()[i] 是查找枚举实例的非常简单且有效的方法。相反,ordinal() 方法返回枚举实例的索引。

有没有办法按字母顺序输出枚举的值?我是否需要一个单独的比较器对象,或者是否有内置的方法可以做到这一点?基本上我希望根据 getDescription() 文本按字母顺序对值进行排序:

您所说的 value 并不是一般为枚举定义的东西。这里,在您的上下文中,您指的是 getDescription() 的结果。

正如您所说,您可以为这些描述创建一个比较器。这将是完美的:-)


请注意,一般来说,您可能需要这些实例的多个订单

  • 声明订单(这是官方订单)
  • 描述订单
  • 根据需要其他

订单您还可以推动 DescriptionComparator 的概念一点点:

  1. 出于性能原因,您可以存储计算的描述。

  2. 因为枚举不能继承,所以代码重用必须在枚举类之外。让我举一个我们将在项目中使用的示例:

现在是代码示例...

/** 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);

请注意,EnumUtils 中的通用代码不仅适用于一个枚举类,而且适用于任何枚举类在实现Described接口的项目中。

如前所述,将代码放在枚举之外(本来应该属于的位置)的目的是重用代码。对于两个枚举来说这没什么大不了的,但是我们的项目中有超过一千个枚举,其中许多具有相同的接口......!

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.

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.

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:

What you call value is not something defined for enums in general. Here, in your context, you mean the result of getDescription().

As you say, you could create a Comparator for these descriptions. 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:

  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.

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...!

岁月如刀 2024-08-17 20:00:23

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

Just sort them using Arrays.sort and your own comparator.

乖乖兔^ω^ 2024-08-17 20:00:23

您可以在java8中使用带比较器的排序函数

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

You can use sorted function with comparator in java8

enumlist.stream()
.sorted(Comparator.comparing(Enum::toString)).collect(Collectors.toList());
酸甜透明夹心 2024-08-17 20:00:23

这是一种对任何类执行此操作的通用方法,无需在要排序的类上实现 Comparable 或创建自定义比较器。我发现在某些情况下我不想覆盖compareTo,因为它有不同的目的,无论如何你都不能用于枚举,并且不断创建包装类是一种痛苦。您可以传入一个函数,该函数输出您想要用于排序目的的 Comparable 对象。

toComparable 函数仅对列表中的每个元素调用一次(对于自定义比较器则不然),因此如果该调用对于某些类来说成本较高,则特别好。空值在内部处理,因此它比自定义比较器更容易使用。对 Java 7 的 TimSort 算法的一次调用比对 SortedMap(红黑树或其他平衡树实现)进行一堆 O(log N) 插入要高效得多。而且您不限于任何特定的类或接口。

在许多情况下,现实世界的性能提升是显着的。例如,在大小为 100k 的列表上使用 toString() 对 Double 进行排序时,性能提升大约是使用比较器的 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);
       }
    }
}

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.

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.

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.

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);
       }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文