views:

1153

answers:

4

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:

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:

Alpha
Beta
Gamma
Omega
+5  A: 

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

Dmitry
+4  A: 

This SO question discusses implementing comparators for enums.

Kaleb Brasee
+5  A: 
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.

meriton
Thanks, this is a nice and simple way to do it
denchr
But why use a `Map`? Nothing is done with the keys, so it doesn't carry very well the intention, does it? Using a `SortedSet` (implementation `TreeSet`) would correspond better. But the uniqueness that characterizes a `Set` (or the keys of a `Map`) is not mentionned as requisite in the original post, so I suggest using a simpler (and more efficient) `List<String>`, followed by a `Collections.sort()` call.
KLE
The keys are sorted by, the values are returned. The question states: "Basically I would like the values to be alphabetically sorted based on the getDescription() text:", so perhaps printing the enums is not all he has in mind.
meriton
Good point about the uniqueness of descriptions. Have edited to include it.
meriton
@meriton Thanks for your appreciation. As I commented in my answer, the word "value" in the original post is not defined, but I understand it as the value of the *description* field. In your code sample and your comment, you assume "value" means `instance`. (For sure, in my code, I would agree with you ; but for joel_nc ???)
KLE
+3  A: 

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

KLE
That is a thorough explanation. Thank you.
denchr