将枚举组合作为键映射

时间:2014-03-03 14:32:42

标签: java map enums

我想知道是否存在任何Map<K, V>实现,其中包含2个或更多枚举的枚举。

我将提供一个简化的例子。

说我有两个枚举DiceEyesCardSuit

public enum DiceEyes {
    ONE, TWO, THREE, FOUR, FIVE, SIX
}

public enum CardSuit {
    HEARTS, DIAMONDS, SPADES, CLUBS
}

现在我有6 * 4 = 24张图片,根据用户在GUI中选择的内容,我想从中显示一张图片 - 他选择了DiceEyesCardSuit

我无法控制图像的文件名。因此,通过命名图像<DiceType>-<CardSuit>-.png或任何其他方式,我都无法聪明。因此,我需要将DiceTypeCardSuit的组合映射到文件名。

我已经考虑过在[{1}} EnumMap EnumMap上运行的解决方案:

EnumMap<DiceType, EnumMap<CardSuit, String>> ... = new ...;

但这看起来过于复杂。然后,同事会认为DiceTypeCardSuit更重要或更不重要,查看类型的顺序。

为此目的介绍一个包装类对我来说似乎有些过分。当我必须在Map中使用它时,我需要实现equals()hashCode(),为此目的看起来太多了。有了枚举,你已经保证了对象的平等性,所以我想继续使用枚举。

如果不引入特定的课程或过多的开销,如何实现这一目标?

6 个答案:

答案 0 :(得分:4)

我会创建一个Pair<A, B>类,然后您可以使用地图:

Map<Pair<DiceEyes, CardSuit>, String> = new HashMap<>();

答案 1 :(得分:3)

我已经知道实现了一个ArrayKey对象,它允许我在地图等中使用数组作为键。

public class ArrayKey {
   private Object[] array;
   public ArrayKey(Object... array) {
       this.array = array;
   }
   public boolean equals(Object other) { ... }
   public int hashCode() { ...}
   public Object[] getArray() { return array; }
}

然后你可以这样做:

Map<ArrayKey, String> map = new HashMap();
map.put(new ArrayKey(DiceEyes.ONE,CardSuit.HEARTS), "/path/to/file.jpg");
map.get(new ArrayKey(DiceEyes.ONE,CardSuit.HEARTS));

当然,为方便起见,可以扩展为创建一个ArrayKeyMap

public class ArrayKeyMap<T> {
   private Map<ArrayKey, T> map = new HashMap();
   public T put(Object... key, T value) {
      return map.put(new ArrayKey(key), value);
   }
   public T get(Object... key) {
      return map.get(new ArrayKey(key));
   }
}

答案 2 :(得分:1)

使用Enum.name()方法创建字符串作为键怎么样?

String key=DiceEyes.ONE.name()+CardSuit.HEARTS.name(); //"ONEHEARTS".

答案 3 :(得分:1)

不幸的是,这种灵活性是不可能的。地图被定义为<K, V>,基本就是那个。您提供的唯一方法是:创建关键对象或使用地图地图。 (或者我想你也可以编写自己的Map实现。)

由于你使用的是enum,所以制作一个包装器对象实际上很方便,但是我建议稍微改一下它。您可以使其不可变,并且每对只有一个实例。这将避免对象创建。如果需要,您可以覆盖equals,但由于每对中只有一个,因此身份就足够了。您可以使用==来比较它们,这也意味着您可以使用IdentityHashMap。

public final class DiceCardPair {
    private final DiceEyes eyes;
    private final CardSuit suit;

    private DiceCardPair(
        final DiceEyes eyes,
        final CardSuit suit
    ) {
        this.eyes = eyes;
        this.suit = suit;
    }

    @Override
    public int hashCode() {
        // very compact hash code
        // make shift bigger if more constants
        return eyes.ordinal() | suit.ordinal() << 3;
    }

    @Override
    public boolean equals(Object obj) {
        if(!(obj instanceof DiceCardPair)) {
            return false;
        }

        DiceCardPair pair = (DiceCardPair)obj;
        return eyes == pair.eyes && suit == pair.suit;
    }

    private static final DiceCardPair[][] values;
    static {
        DiceEyes[] eyes = DiceEyes.values();
        CardSuit[] suits = CardSuit.values();

        values = new DiceCardPair[eyes.length][suits.length];
        for(int i = 0; i < values.length; i++) {
            for(int k = 0; k < values[i].length; k++) {
                values[i][k] = new DiceCardPair(
                    eyes[i], suits[k]
                );
            }
        }
    }

    public static DiceCardPair valueOf(DiceEyes e, CardSuit s) {
        return values[e.ordinal()][s.ordinal()];
    }
}

你甚至不必直接使用这样的类的实例,例如:

Value v = map.get(DiceCardPair.valueOf(DiceEyes.ONE, CardSuit.SPADES));
if(v == null) {
    map.put(DiceCardPair.valueOf(DiceEyes.ONE, CardSuit.SPADES), new Value());
}

答案 4 :(得分:0)

实际问题

  

如果不引入特定的课程或过多的开销,如何实现这一目标?

已经回答:完全没有。

所以虽然它被明确排除在问题之外,但我想引入一个通用的Pair类,它可以派上用场,就像这样的案例。

final class Pair<T>
{
    public static <T, TT extends T> Pair<T> of(TT t0, TT t1)
    {
        return new Pair<T>(t0, t1);
    }

    private final T first;
    private final T second;

    private Pair(T first, T second)
    {
        this.first = first;
        this.second = second;
    }


    @Override
    public String toString()
    {
        return "(" + first + "," + second + ")";
    }

    @Override
    public boolean equals(Object object)
    {
        if(object instanceof Pair)
        {
            Pair<?> other = (Pair<?>) object;
            return 
                equal(this.first, other.first) && 
                equal(this.second, other.second);
        }
        return false;
    }

    private static <U> boolean equal(U a, U b)
    {
        if (a == null)
        {
            return b == null;
        }
        return a.equals(b);
    }


    @Override
    public int hashCode()
    {
        return
            ((first == null) ? 0 : first.hashCode()) ^ 
            ((second == null) ? 0 : second.hashCode());
    }

    public T getFirst()
    {
        return first;
    }

    public T getSecond()
    {
        return second;
    }
}

答案 5 :(得分:0)

使用Pair类作为密钥。你可以在其他地方重复使用它,所以这不是一种矫枉过正。不幸的是,Java没有像其他语言(c ++,c#)那样的内置实现,但是这篇文章中有一个直接的实现:

A Java collection of value pairs? (tuples?)