允许分别提供等比较器和散列函数的映射

Har*_*ald 7 java hashmap symbolic-math polynomials

在尝试对多项式进行建模时,特别是它们的乘法,我遇到了以下问题.在乘法期间,两个多项式的单个单项式相乘,当然可以发生我有(3x ^ 2 y + 5x y ^ 2)*(x + y).结果包含3x ^ 2 y ^ 2和5 x ^ 2 y ^ 2,我想通过添加立即组合.

当然,我想使用单项式的部分x ^ 2 y ^ 2作为(哈希)映射中的关键字来添加不同的系数(在示例中为3和5).但是我设想的单项式对象自然也应该包含系数,该系数应该是地图键的一部分.

当然,我可以写单项对象的equals/hashcode,使它们忽略系数.但这感觉错了,因为数学上单项式显然只等于另一个,如果系数相等的话.

为中间操作引入无系数单项式对象也看起来不正确.

我没有使用地图,而是使用列表并使用二进制搜索和一个忽略系数的专用比较器.

如果没有使用不使用密钥'equals/hashcode的地图,而是使用专用的地图,那么有没有更好的想法如何融合单项式?

NoD*_*und 5

由于 JDK 实现[Linked]HashMap不允许您覆盖equals/hashCode实现,因此唯一的其他方法是:

  • 一个像这样的包装对象:

      class A {
        private final String fieldA; // equals/hashCode based on that field.
        private final String fieldB; // equals/hashCode based on that field.
      }
    
      class B {
        private A a;
        public int hashCode() {return a.fieldA.hashCode();} 
        public boolean equals(Object o) {... the same ... }
      }
    
      Map<B, Value> map = new HashMap<B, Value>();
      map.put(new B(new A("fieldA", "fieldB")), new Value(0));
    
    Run Code Online (Sandbox Code Playgroud)

    好吧,有更多的吸气剂/构造函数。

    这可能很烦人,而且可能存在一些库(如 Guava),它允许给定一个 equals/hashCode 方法,就像给一个Comparatorto 一样TreeMap

    您将在下面找到一个示例实现,它指出如何装饰现有地图。

  • 将 aTreeMap与特定的Comparator. 另一个答案指出了这一点,但我会说您需要正确定义 a ,Comparator因为这可能会导致问题:如果您的compareTo方法在达到相等时返回 0,在其他情况下返回 1,这意味着没有自然排序。您应该尝试找到一个,或者使用包装器对象。


如果你想接受挑战,你可以使用委托/装饰来创建一个基本的实现HashMap(这可能是另一种地图,比如LinkedHashMap):

public class DelegatingHashMap<K,V> implements Map<K,V> {
  private final BiPredicate<K,Object> equalsHandler;
  private final IntFunction<K> hashCodeHandler;
  private final Map<Wrapper<K>,V> impl = new HashMap<>();

  public DelegatingHashMap(
    BiPredicate<K,Object> equalsHandler,
    IntFunction<K> hashCodeHandler
  ) {
    this.equalsHandler = requireNonNull(equalsHandler, "equalsHandler");
    this.hashCodeHandler= requireNonNull(hashCodeHandler, "hashCodeHandler");
  }

  public Object get(K key) {
    Wrapper<K> wrap = new Wrapper<>(key);
    return impl.get(wrap);
  }  

  ...

  static class Wrapper<K2> {
    private final K2 key;
    private final BiPredicate<K> equalsHandler;
    private final IntFunction<K> hashCodeHandler;
    public int hashCode() {return hashCodeHandler.apply(key);}
    public boolean equals(Object o) {
      return equalsHandler.test(key, o);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

以及使用地图的代码:

DelegatingHashMap<String, Integer> map = new DelegatingHashMap<>(
  (key, old) -> key.equalsIgnoreCase(Objects.toString(o, "")),
  key -> key.toLowerCase().hashCode()
);
map.put("Foobar", 1);
map.put("foobar", 2);

System.out.println(map); // print {foobar: 2}
Run Code Online (Sandbox Code Playgroud)

但也许最好的(对于内存)是重写HashMap直接使用处理程序而不是包装器。