2

我想检查 2 之间的相等性HashMap<Number,String>。我的想法是将每个 Number 转换为 BigDecimal withnew BigDecimal(number.toString())然后检查相等性,而不是比较 2 Maps 时使用compareTo() == 0的基本值。equals

谁有一个很好的实现,甚至更好:一个更好的想法?

4

1 回答 1

0

这看起来很像XY 问题;正如评论中所指出的,比较任意Number对象没有多大意义;为什么不直接制作地图Map<BigDecimal, String>并始终直接使用(BigDecimal必要时使用标准化)?stripTrailingZeros()然后你可以使用标准Map相等。考虑退后一步,首先询问您是否真的需要您所描述的行为。

值得注意的是,Number没有实现Comparable,这应该是一个非常明确的提示,您不应该尝试比较任意Number实例。


如果由于某种原因这不是一个选项,那么这是您所描述行为的合理实现。

private static BigDecimal toBigDecimal(Number n) {
  return n instanceof BigDecimal ? (BigDecimal)n : new BigDecimal(n.toString());
}

public static <V> boolean numberMapEquality(
    Map<Number, ? extends V> a, Map<Number, ? extends V> b) {
  if (a == b) return true;
  if (a.size() != b.size()) return false;

  // TreeMap uses .compareTo(), not .equals()
  TreeMap<BigDecimal, V> bdMap = new TreeMap<>();
  for (Entry<Number, ? extends V> e : a.entrySet()) {
    bdMap.put(toBigDecimal(e.getKey()), e.getValue());
  }

  if (bdMap.size() != a.size()) {
    // comment out if you don't care about this edge-case - but you should
    throw new IllegalArgumentException(
        "Multiple keys in 'a' normalize to the same value; " +
        "equality comparison is unsafe.");
  }

  // Taken from AbstractMap.equals()
  for (Entry<Number, ? extends V> e : b.entrySet()) {
    BigDecimal bdKey = toBigDecimal(e.getKey());
    V value = e.getValue();
    if (value == null) {
      if (!(bdMap.get(bdKey)==null && bdMap.containsKey(bdKey)))
        return false;
    } else {
      if (!value.equals(bdMap.get(bdKey)))
        return false;
    }
  }
  return true;
}

或者,只需将两个映射复制到TreeMap<BigDecimal, V>并调用.equals(),但这需要复制两个映射,而numberMapEquality()只需要复制一个,如果它们的大小不同,则避免任何复制,并检测键冲突。

于 2016-11-11T20:41:45.860 回答