简体   繁体   中英

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

I would like to check equality between 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.

Who has a good implementation of this, or even better : a better idea ?

This seems a lot like an XY problem ; as pointed out in the comments it doesn't make a lot of sense to be comparing arbitrary Number objects; why not just make your maps Map<BigDecimal, String> and just always use BigDecimal directly ( normalized with stripTrailingZeros() if necessary)? Then you can just use standard Map equality. 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.


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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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