7

Is there a one-liner to convert a list of String to a set of enum? For instance, having:

public enum MyVal {
    ONE, TWO, THREE
}

and

List<String> myValues = Arrays.asList("ONE", "TWO", "TWO");

I'd like to convert myValues to a Set<MyVal> containing the same items as:

EnumSet.of(MyVal.ONE, MyVal.TWO)
Tunaki
  • 132,869
  • 46
  • 340
  • 423
pablo
  • 747
  • 1
  • 10
  • 24

2 Answers2

21

Yes, you can make a Stream<String> of your elements, map each of them to the respective enum value with the mapper MyVal::valueOf and collect that into a new EnumSet with toCollection initialized by noneOf:

public static void main(String[] args) {
    List<String> myValues = Arrays.asList("ONE", "TWO", "TWO");
    EnumSet<MyVal> set =
        myValues.stream()
                .map(MyVal::valueOf)
                .collect(Collectors.toCollection(() -> EnumSet.noneOf(MyVal.class)));
    System.out.println(set); // prints "[ONE, TWO]"
}

If you are simply interested in having a Set as result, not an EnumSet, you can simply use the built-in collector Collectors.toSet().

Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • 5
    Does that count as a one-liner these days :-) ? – Thilo Mar 07 '16 at 09:26
  • Depends on the number of characters per line you allow. SO is stingy in that regard. – the8472 Mar 07 '16 at 09:31
  • 1
    Instead of `Collectors.toCollection(() -> EnumSet.noneOf(MyVal.class))` I'm doing `Collectors.toSet()` with the same result – pablo Mar 07 '16 at 09:37
  • 5
    @otonakav: you asked for an `EnumSet` explicitly. If any `Set` is sufficient, you can use `toSet()`, but then don’t ask for an `EnumSet`… – Holger Mar 07 '16 at 10:13
  • @Holger I've asked for a `Set` containing the same items as an `EnumSet` – pablo Mar 07 '16 at 10:17
  • 4
    @otonakav: maybe it’s just me, but the title of your question reads like “*Convert a List to an EnumSet with Java 8*”. Clearly “to an **EnumSet**” Believe me, Tunaki knows that there is `Collectors.toSet()`; the posted solution `toCollection(() -> EnumSet.noneOf(MyVal.class))` is just for your specific question. – Holger Mar 07 '16 at 10:20
  • 1
    @Holger Tunaki changed the title of my question but it is not a big deal. – pablo Mar 07 '16 at 10:22
  • 2
    @Holger Actually, I rephrased the title to that because initially it was "convert to a set of enum" and since the OP said "containing same items as EnumSet", I "clarified" the title "convert to an EnumSet"... Looks like it wasn't true. – Tunaki Mar 07 '16 at 10:23
  • 3
    I suggest fixing the title and expanding the answer as `toSet()` clearly is easier to use when the type of the `Set` doesn’t matter. – Holger Mar 07 '16 at 10:26
3

Here's a two-liner (but shorter):

EnumSet<MyVal> myVals = EnumSet.allOf(MyVal.class);
myVals.removeIf(myVal -> !myValues.contains(myVal.name()));

Instead of adding elements present on the list, you could create an EnumSet with all possible values and remove the ones that are not present on the list.

fps
  • 33,623
  • 8
  • 55
  • 110
  • 1
    Interesting. It has the slightly different property that it doesn't throw an exception if any of the strings doesn't match an enum. Might or might not be desirable, depending on the situation. – slim Sep 30 '16 at 08:55