【问题标题】:Optimize Enum Lookup Map优化枚举查找映射
【发布时间】:2013-07-13 13:41:16
【问题描述】:

我想知道是否有更好的方法来创建和搜索下面的静态地图。如main() 方法中所见。

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public enum PokemonType {
  BUG("Bug"),
  DARK("Dark"),
  DRAGON("Dragon"),
  ELECTRIC("Electric"),
  FAIRY("Fairy"),
  FIGHTING("Fighting"),
  FIRE("Fire"),
  FLYING("Flying"),
  GHOST("Ghost"),
  GRASS("Grass"),
  GROUND("Ground"),
  ICE("Ice"),
  NORMAL("Normal"),
  POISON("Poison"),
  PSYCHIC("Psychic"),
  ROCK("Rock"),
  STEEL("Steel"),
  WATER("Water");

  private String name;

  @SuppressWarnings("serial")
  public static Map<PokemonType, Set<PokemonType>> noEffect = new HashMap<PokemonType, Set<PokemonType>>() {{
    put(BUG, new HashSet<PokemonType>());
    put(DARK, new HashSet<PokemonType>());
    put(DRAGON, new HashSet<PokemonType>());
    put(ELECTRIC, new HashSet<PokemonType>() {{ addAll(Arrays.asList(GROUND)); }});
    put(FAIRY, new HashSet<PokemonType>());
    put(FIGHTING, new HashSet<PokemonType>() {{ addAll(Arrays.asList(GHOST)); }});
    put(FIRE, new HashSet<PokemonType>());
    put(FLYING, new HashSet<PokemonType>());
    put(GHOST, new HashSet<PokemonType>() {{ addAll(Arrays.asList(NORMAL)); }});
    put(GRASS, new HashSet<PokemonType>());
    put(GROUND, new HashSet<PokemonType>() {{ addAll(Arrays.asList(FLYING)); }});
    put(ICE, new HashSet<PokemonType>());
    put(NORMAL, new HashSet<PokemonType>() {{ addAll(Arrays.asList(GHOST)); }});
    put(POISON, new HashSet<PokemonType>());
    put(PSYCHIC, new HashSet<PokemonType>());
    put(ROCK, new HashSet<PokemonType>());
    put(STEEL, new HashSet<PokemonType>());
    put(WATER, new HashSet<PokemonType>());
  }};

  @SuppressWarnings("serial")
  public static Map<PokemonType, Set<PokemonType>> notVeryEffective = new HashMap<PokemonType, Set<PokemonType>>() {{
    put(BUG, new HashSet<PokemonType>() {{ addAll(Arrays.asList(FIGHTING,FIRE,FLYING,GHOST,POISON,STEEL)); }});
    put(DARK, new HashSet<PokemonType>() {{ addAll(Arrays.asList(DARK,FIGHTING,STEEL)); }});
    put(DRAGON, new HashSet<PokemonType>() {{ addAll(Arrays.asList(STEEL)); }});
    put(ELECTRIC, new HashSet<PokemonType>() {{ addAll(Arrays.asList(DRAGON,ELECTRIC)); }});
    put(FAIRY, new HashSet<PokemonType>());
    put(FIGHTING, new HashSet<PokemonType>() {{ addAll(Arrays.asList(BUG,FLYING,POISON,PSYCHIC)); }});
    put(FIRE, new HashSet<PokemonType>() {{ addAll(Arrays.asList(DRAGON,FIRE,ROCK,WATER)); }});
    put(FLYING, new HashSet<PokemonType>() {{ addAll(Arrays.asList(ROCK,STEEL)); }});
    put(GHOST, new HashSet<PokemonType>() {{ addAll(Arrays.asList(STEEL)); }});
    put(GRASS, new HashSet<PokemonType>() {{ addAll(Arrays.asList(BUG,DRAGON,FIRE,FLYING,GRASS,POISON,STEEL)); }});
    put(GROUND, new HashSet<PokemonType>() {{ addAll(Arrays.asList(BUG,GRASS)); }});
    put(ICE, new HashSet<PokemonType>() {{ addAll(Arrays.asList(FIRE,ICE,STEEL,WATER)); }});
    put(NORMAL, new HashSet<PokemonType>() {{ addAll(Arrays.asList(ROCK,STEEL)); }});
    put(POISON, new HashSet<PokemonType>() {{ addAll(Arrays.asList(GHOST,GROUND,POISON,ROCK)); }});
    put(PSYCHIC, new HashSet<PokemonType>() {{ addAll(Arrays.asList(PSYCHIC,STEEL)); }});
    put(ROCK, new HashSet<PokemonType>() {{ addAll(Arrays.asList(FIGHTING,GROUND,STEEL)); }});
    put(STEEL, new HashSet<PokemonType>() {{ addAll(Arrays.asList(ELECTRIC,FIRE,STEEL,WATER)); }});
    put(WATER, new HashSet<PokemonType>() {{ addAll(Arrays.asList(DRAGON,GRASS,WATER)); }});
  }};

  @SuppressWarnings("serial")
  public static Map<PokemonType, Set<PokemonType>> superEffective = new HashMap<PokemonType, Set<PokemonType>>() {{
    put(BUG, new HashSet<PokemonType>() {{ addAll(Arrays.asList(DARK,GRASS,PSYCHIC)); }});
    put(DARK, new HashSet<PokemonType>() {{ addAll(Arrays.asList(GHOST,PSYCHIC)); }});
    put(DRAGON, new HashSet<PokemonType>() {{ addAll(Arrays.asList(DRAGON)); }});
    put(ELECTRIC, new HashSet<PokemonType>() {{ addAll(Arrays.asList(FIRE,WATER)); }});
    put(FAIRY, new HashSet<PokemonType>());
    put(FIGHTING, new HashSet<PokemonType>() {{ addAll(Arrays.asList(DARK,ICE,NORMAL,ROCK,STEEL)); }});
    put(FIRE, new HashSet<PokemonType>() {{ addAll(Arrays.asList(BUG,GRASS,ICE,STEEL)); }});
    put(FLYING, new HashSet<PokemonType>() {{ addAll(Arrays.asList(BUG,FIGHTING,GRASS)); }});
    put(GHOST, new HashSet<PokemonType>() {{ addAll(Arrays.asList(GHOST,PSYCHIC)); }});
    put(GRASS, new HashSet<PokemonType>() {{ addAll(Arrays.asList(GROUND,ROCK,WATER)); }});
    put(GROUND, new HashSet<PokemonType>() {{ addAll(Arrays.asList(ELECTRIC,FIRE,POISON,ROCK,STEEL)); }});
    put(ICE, new HashSet<PokemonType>() {{ addAll(Arrays.asList(DRAGON,FLYING,GRASS,GROUND)); }});
    put(NORMAL, new HashSet<PokemonType>());
    put(POISON, new HashSet<PokemonType>() {{ addAll(Arrays.asList(GRASS)); }});
    put(PSYCHIC, new HashSet<PokemonType>() {{ addAll(Arrays.asList(FIGHTING,POISON)); }});
    put(ROCK, new HashSet<PokemonType>() {{ addAll(Arrays.asList(BUG,FIRE,FLYING,ICE)); }});
    put(STEEL, new HashSet<PokemonType>() {{ addAll(Arrays.asList(ICE,PSYCHIC)); }});
    put(WATER, new HashSet<PokemonType>() {{ addAll(Arrays.asList(FIRE,GROUND,ROCK)); }});
  }};

  public float getModifier(PokemonType opponentType) {
    if (PokemonType.superEffective.get(this).contains(opponentType))
      return 2.0f;
    if (PokemonType.notVeryEffective.get(this).contains(opponentType))
      return 0.5f;
    if (PokemonType.noEffect.get(this).contains(opponentType))
      return 0.0f;
    return 1.0f;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String shortName() {
    return this.name.substring(0, 3);
  }

  private PokemonType(String name) {
    this.name = name;
  }

  public static void main(String[] args) {
    assert(PokemonType.ELECTRIC.getModifier(PokemonType.WATER) == 2.0f);
    assert(PokemonType.GROUND.getModifier(PokemonType.DARK) == 1.0f);
    assert(PokemonType.FIRE.getModifier(PokemonType.DRAGON) == 0.5f);
    assert(PokemonType.NORMAL.getModifier(PokemonType.GHOST) == 0.0f);
  }
}

【问题讨论】:

  • 您对“更好”的要求是什么? (这与运行时性能有关吗?可读性?让编译器验证完整性?从 excel 中轻松导入矩阵的能力?完全是别的东西吗?)

标签: java optimization enums hashmap set


【解决方案1】:

我会使用ImmutableMapUnmodifiableMap,因为地图一旦被填充就不应被修改。

另外,我将创建一个 Map&lt;List&lt;PokemonType&gt;, Float&gt;,其中每个列表将包含两个 PokemonType 对象(第一个对象是攻击者,第二个对象是防御者,反之亦然 - 没关系只要它是一致的)。或者,我会创建一个Map&lt;PokemonTypePair, Float&gt;,其中PokemonTypePair

public class PokemonTypePair {
    final public PokemonType attacker;
    final public PokemonType defender;

    public boolean equals(Object obj) {
        if(obj == null) return false;
        else if(!(obj instanceof PokemonTypePair)) return false;
        else {
            PokemonTypePair other = (PokemonTypePair)obj;
            return this.attacker.equals(other.attacker) &&
                this.defender.equals(other.defender);
        }
    }

    public int hashCode() {
        return (997 * attacker == null ? 0 : attacker.hashCode()) ^
            (991 * defender == null ? 0 : defender.hashCode());
    }
}

每个映射条目的 float 将为 0.0、0.5、1.0 或 2.0;或者,忽略具有 1.0 值的映射条目,并假设缺少的映射条目对应于 1.0 值。

如果配对是自反的(这意味着谁是攻击者,谁是防御者并不重要——我不知道 pokemon 是如何工作的),那么你只需要一个 PokemonType pokemon1 字段和一个 PokemonType pokemon2 字段;将字母顺序较低的 PokemonType 放在pokemon1 字段中,将字母顺序较高的 PokemonType 放在pokemon2 字段中,以简化equals 方法。同样,如果您使用List&lt;List&lt;PokemonType&gt;&gt; 方法,请按字母顺序对内部列表进行排序,或者改用List&lt;Set&lt;PokemonType&gt;&gt;

这样,给定任何两种口袋妖怪类型,您只需要在单个地图中查找这对来找到乘数,而不必检查多个地图。

如果您想快速找到无效/超级有效/等的配对,则维护单独的无效/超级有效/等配对列表或集合,即List&lt;List&lt;PokemonType&gt;&gt; ineffectivePairingList&lt;PokemonPairing&gt; ineffectivePairing

【讨论】:

    【解决方案2】:

    如果您有一个带有 Enum 键的 Map 或一个带有枚举值的 Set,则使用 E​​numMap 或 EnumSet 会更有效,因为它们是为这种情况而设计的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-14
      • 2017-03-03
      相关资源
      最近更新 更多