简体   繁体   English

如何检查2 HashMap之间的相等性 <Number, String> ?

[英]How to check equality between 2 HashMap<Number, String>?

I would like to check equality between 2 HashMap<Number,String> . 我想检查2 HashMap<Number,String>之间的相等性。 My idea is converting each Number into BigDecimal with new BigDecimal(number.toString()) and then check equality with compareTo() == 0 instead of the basic equals that is used when comparing 2 Maps. 我的想法是使用new BigDecimal(number.toString())将每个Number转换为BigDecimal,然后使用compareTo() == 0而不是比较2个Map时使用的基本equals来检查相等性。

Who has a good implementation of this, or even better : a better idea ? 谁能很好地实现这一目标,甚至更好:更好的主意?

This seems a lot like an XY problem ; 这看起来很像XY问题 ; as pointed out in the comments it doesn't make a lot of sense to be comparing arbitrary Number objects; 如评论中所指出的,比较任意Number对象没有多大意义; why not just make your maps Map<BigDecimal, String> and just always use BigDecimal directly ( normalized with stripTrailingZeros() if necessary)? 为什么不只让您的地图Map<BigDecimal, String>并始终直接直接使用BigDecimal (必要时使用stripTrailingZeros() 标准化 )? Then you can just use standard Map equality. 然后,您可以使用标准Map相等性。 Consider stepping back and asking whether you really need the behavior you're describing in the first place. 考虑退后一步,询问您是否真的需要您首先描述的行为。

Notably, Number doesn't implement Comparable , which should be a pretty clear hint that you shouldn't try to compare arbitrary Number instances. 值得注意的是, Number没有实现Comparable ,这应该是一个很明确的提示,即您不应该尝试比较任意Number实例。


If that isn't an option for some reason, here's a reasonable implementation of the behavior you're describing. 如果由于某种原因这不是一个选择,则这是您描述的行为的合理实现。

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;
}

Alternatively just copy both maps to TreeMap<BigDecimal, V> and call .equals() , but that requires copying both maps, whereas numberMapEquality() only needs to copy one, avoids any copying if they're not the same size, and detects key collisions. 另外,也可以将两个地图都复制到TreeMap<BigDecimal, V>并调用.equals() ,但这需要复制两个地图,而numberMapEquality()只需要复制一个,避免大小不相同的任何复制,并检测按键碰撞。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM