2

I have an array of integers and need to convert it to an array of enums.

enum my_enum {
    APPLE, BANANA, ORANGE;
    int getColorAsInt() { ... }
};
int[] foo = some_method_i_cannot_modify();
my_enum[] bar = ??? ( foo );

What is the easiest way to do that?

Here I found a way to convert a single integer to an enum value (they are using a Color enum in their example):

public static Color convertIntToColor(int iColor) {
    for (Color color : Color.values()) {
        if (color.getColorAsInt() == iColor) {
            return color;
        }
    }
    return null;
}

... but I hope there is a more direct way to do that conversion (otherwise in my code it doesnt make sense to use an enum in the first place).

Here is a SO question about converting a single integer to enum value.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • Well what is the integer you will get, and what does `getColorAsInt` return? – daniu Apr 03 '18 at 13:11
  • 2
    Possible duplicate of [Convert from enum ordinal to enum type](https://stackoverflow.com/questions/609860/convert-from-enum-ordinal-to-enum-type) - assuming your integers represent the enum ordinals, that is – Alex Savitsky Apr 03 '18 at 13:11
  • @daniu not sure if I understand your question. I am certain that my integers are in the valid range and the function I am looking for is supposed to return the enum value for a given integer, preferably arrays of integers as input and an array of enum values as output. – 463035818_is_not_an_ai Apr 03 '18 at 13:12
  • @AlexSavitsky actually I would agree with the duplicate, but as the answers here already suggest solutions that go beyond the answers in the dupe, I just added a note in the question – 463035818_is_not_an_ai Apr 03 '18 at 13:23
  • 1
    @user463035818 I mostly mark the duplicates to provide an easy access to related questions and/or answers, not with the intention to close the dupe. The SO lacks the feature to mark a question as "related" (e.g., like in JIRA) without closing it as a duplicate. The answer does indeed provide useful information beyond what's linked – Alex Savitsky Apr 03 '18 at 14:05
  • @AlexSavitsky yeah no problem. I just had the same case just with me on the other side. Imho flagging as duplicate for the reasons you mention is just fine, it is just that new users (including me some time ago) immediately panic when they think their question is going to be closed just because something remotely similar has been asked before – 463035818_is_not_an_ai Apr 03 '18 at 14:08

7 Answers7

4

You need to use a loop or stream to iterate through the input array of integers and map each to the Color instance. Try this:

int[] array = getArrayOfInts();
Color[] colors = Arrays.stream(array)
            .mapToObj(i -> convertIntToColor(i))
            .filter(Objects::nonNull)
            .toArray(Color[]::new);
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
Vladimir Vagaytsev
  • 2,871
  • 9
  • 33
  • 36
  • can this be improved in case this is executed many times with different arrays (but same enum of course) ? Btw, I know that the integers are in the valid range, does that mean I can skip the `filter(Objects::nonNull)` ? – 463035818_is_not_an_ai Apr 03 '18 at 13:19
  • Do you mean performance improvements? I'd prefer either to keep `filter()` call (because the `convertIntToColor ()` *may* return `null` by design) or change the method impl and return special non-`null` value instead, you may introduce `Color.UNKNOWN` instance to denote the unrecognized color. – Vladimir Vagaytsev Apr 03 '18 at 13:24
4

It depends on what is in your foo array. If it is the ordinals of the enums then something as simple as this should suffice.

enum my_enum { APPLE, BANANA, ORANGE };
int[] foo = {0,2,2,1};
public void test(String[] args) {
    my_enum[] bar = new my_enum[foo.length];
    for (int i = 0; i < foo.length; i++) {
        bar[i] = my_enum.values()[foo[i]];
    }
    System.out.println(Arrays.toString(bar));
}

prints

[APPLE, ORANGE, ORANGE, BANANA]

A streams equivalent would be something like:

    my_enum[] es = Arrays.stream(foo)
            .mapToObj(i -> my_enum.values()[i])
            .toArray(my_enum[]::new);
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • 3
    Looks good. The only improvement i’d suggest is to only call values() once. This allocates a new array every time. – cpp beginner Apr 03 '18 at 13:23
  • It assumes that the `int` values be "synchronized" with the enum values declaration order and `int` values of the array are in a very specific range 0 to number of enum values -1. It makes a lot of assumptions. – davidxxx Apr 03 '18 at 13:32
  • @cppbeginner I hope the compiler do the optimization for us, and that `values()` is only an accessor. Better test that this makes any time inprovement before doing a "premature optimization" – pdem Apr 03 '18 at 13:35
  • @pdem It would be good if the compiler did such optimisation but according to this answer (from 2015) it doesn’t. https://stackoverflow.com/a/32804662/6253321 – cpp beginner Apr 03 '18 at 13:45
  • 1
    @davidxxx - I thought I had covered those in my first two sentences. – OldCurmudgeon Apr 03 '18 at 13:57
  • @cppbeginner indeed, it doesn't and it cannot since arrays are mutable. – pdem Apr 03 '18 at 14:02
1

this one line of code will return array of object and you can access enum by arr[0]

Object[] arr = Arrays.stream(my_enum.values()).map(x->x).toArray();
Navin Gelot
  • 1,264
  • 3
  • 13
  • 32
0

but I hope there is a more direct way to do that conversion

You don't have not the choice. as you have int values and you want to convert them into enum values.
So for each ints you necessarily need to find the enum value corresponding to and that whatever the way.

You have a straighter way as using the order of the enum in its declaration
but it is a very error prone approach and it assumes that the int values start to 0 and are incremented by 1.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • to find the enum value from the integer value it is not necessary to loop over the whole enum for each lookup. Thats what I meant with "more direct". What do you mean with error prone? – 463035818_is_not_an_ai Apr 03 '18 at 13:15
  • You could use a Map for a direct access but note that in terms of performance iterating on a few elements or using a map doesn't make a great difference. – davidxxx Apr 03 '18 at 13:19
0

If it is your enum, you can of course give it the mapping to begin with.

public enum MyEnum {
    APPLES(10), ORANGES(20);

    private int asInt;
    private MyEnum(int val) {
        asInt = val;
    }
    public int getIntValue() { return asInt; }

    static final Map<Integer, MyEnum> mapping = new HashMap();
    static {
        for (MyEnum e : MyEnum.values()) {
            mapping.put(e.getIntValue(), e);
        }
    }
    static MyEnum fromInteger(int val) {
        return mapping.get(val);
    }
}
daniu
  • 14,137
  • 4
  • 32
  • 53
0

I would make a map, a take a mapped values from there. Of course using its own id is better than ordinal, but to show an idea :

enum Color {
    RED, GREEN, BLUE;

    public static Color[] create(int[] ids) {
        Map<Integer, Color> colors = Arrays.stream(Color.values())
                .collect(Collectors.toMap(Enum::ordinal, Function.identity()));
        return Arrays.stream(ids)
                .mapToObj(colors::get)
                .filter(Objects::nonNull)
                .toArray(Color[]::new);
    }
};

public static void main(String[] args) {
    int[] foo = new int[]{0,1,2};
    System.out.println(Arrays.toString(Color.create(foo)));
}

Outputs

[RED, GREEN, BLUE]
yvoytovych
  • 871
  • 4
  • 12
0

It's better to work on List with Java but there are conversion tools. Also prefer using Java convention: MyEnum.

enum MyEnum {

    APPLE, BANANA, ORANGE;

    public static void main(String[] arg) {
        int[] foo = new int[] { 2, 0, 1 };
        MyEnum[] bar = Arrays.stream(foo).boxed().map(
            i->MyEnum.values()[i]
        ).toArray(MyEnum[]::new);

    }


};

Using array and int make it complicated to use stream, the main part is from int to enum conversion using : i->MyEnum.values()[i] To use this function conversion, you need the map method accessible from a stream.

pdem
  • 3,880
  • 1
  • 24
  • 38