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

标签 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)。但是我设想的单项式对象自然也应该包含系数,它应该是映射键的一部分。

当然,我可以编写单项式对象的等号/哈希码,以便它们忽略系数。但这感觉非常错误,因为从数学上讲,单项式显然只有在系数也相等的情况下才等于另一个单项式。

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

我可以不使用 map ,而是使用列表并使用带有忽略系数的专用比较器的二进制搜索。

除了实现一个不使用键的等值/哈希码的映射,而是一个专用的映射,是否有关于如何融合单项式的更好的想法?

最佳答案

由于 [Linked]HashMap 的 JDK 实现不允许您覆盖 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));
    

    好吧,有更多的 getters/constructors。

    这可能很烦人,也许存在一些库(如 Guava)允许提供 equals/hashCode 方法,就像您可以将 Comparator 提供给 TreeMap .

    您将在下面找到一个示例实现,其中指出了如何装饰现有 map 。

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


如果您想接受挑战,您可以在另一个 HashMap 上使用委托(delegate)/装饰创建一个基本实现(这可能是另一种映射,如 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);
    }
  }
}

以及使用 map 的代码:

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}

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

关于java - 允许分别提供相等比较器和散列函数的映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25773886/

相关文章:

java - Java hashmap 搜索真的是 O(1) 吗?

python - 使用 SymPy 对角化符号矩阵

java - 在 java.nio2 中将路径设置为只读的正确方法

java - 许多线程处于 IN_NATIVE 状态

java - 在双向链表的给定位置搜索节点

matlab - Pretty MuPad : Output of assignment, 表达式和一行结果 - 如何创建该函数?

matlab - 将向量传递给 matlab 函数而不使用 num2cell

java - 用Swing画图 : general approach

Java,确定 HashMap 中是否有任何值与值匹配的最快方法?

java - HashMap 可以有一个由 2 个值组成的键吗?