Ocaml 哈希表中的相等性

发布于 2024-12-28 09:22:22 字数 409 浏览 3 评论 0原文

Ocaml 中是否有哈希表在测试键相等时使用 == 而不是 = ? 例如:

# type foo = A of int;;
# let a = A(1);;
# let b = A(1);;
# a == b;;
- : bool = false
# a = b;;
- : bool = true
# let h = Hashtbl.create 8;;
# Hashtbl.add h a 1;;
# Hashtbl.add h b 2;;
# Hashtbl.find h a;;
- : int = 2
# Hashtbl.find h b;;
- : int = 2

我想要一个可以区分 ab 的哈希表。这可能吗?

Are there hashtables in Ocaml that use == instead of = when testing for equality of keys?
For example:

# type foo = A of int;;
# let a = A(1);;
# let b = A(1);;
# a == b;;
- : bool = false
# a = b;;
- : bool = true
# let h = Hashtbl.create 8;;
# Hashtbl.add h a 1;;
# Hashtbl.add h b 2;;
# Hashtbl.find h a;;
- : int = 2
# Hashtbl.find h b;;
- : int = 2

I'd like a hashtable that can distinguish between a and b. Is that possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北座城市 2025-01-04 09:22:22

您可以使用自定义哈希表:

module H = Hashtbl.Make(struct
  type t = foo
  let equal = (==)
  let hash = Hashtbl.hash
end)

然后在代码中使用 H 而不是 Hashtbl

You can use custom hashtables:

module H = Hashtbl.Make(struct
  type t = foo
  let equal = (==)
  let hash = Hashtbl.hash
end)

And then use H instead of Hashtbl in your code.

淤浪 2025-01-04 09:22:22

托马斯和卡戈的答案中的解决方案在功能上是正确的。如果您按原样使用他们的解决方案,可能会困扰您的一个问题是,如果您散列许多对于 (=) 相等而对于 (= 不同的键,您将遇到比预期更多的冲突=)。事实上,对于 (=) 来说,所有相等的键都具有相同的 Hashtbl.hash 哈希值,并且最终位于同一个存储桶中,在那里它们被识别为不同的 (因为您要求将 (==) 用作相等函数)并创建不同的绑定。在最坏的情况下,哈希表的行为与关联列表具有相同的复杂性(顺便说一下,这是您可以使用的另一种数据结构,然后您不必担心提供哈希函数)。

如果您可以接受偶尔更改的值的键(因此无法从哈希表中检索该值,因为绑定位于错误的存储桶中),则可以使用以下低级函数作为哈希:

external address_of_value: 'a -> int = "address_of_value"

已实现在 C 中为:

#include "caml/mlvalues.h"

value address_of_value(value v)
{
  return (Val_long(((unsigned long)v)/sizeof(long)));
}

然后您将使用:

module H = Hashtbl.Make(struct
  type t = foo 
  let equal = (==) 
  let hash = address_of_value
end);;

The solution in Thomas and cago's answers is functionally correct. One issue that may trouble you if you use their solution as-is is that you will get more collisions than expected if you hash many keys that are equal for (=) and different for (==). Indeed, all keys that are equal for (=) have the same hash for Hashtbl.hash, and end up in the same bucket, where they are they recognized as different (since you asked for (==) to be used as equality function) and create different bindings. In the worst cases, the hash-table will behave with the same complexity as an association list (which, by the way, is another data structure that you could be using, and then you wouldn't have to worry about providing a hash function).

If you can accept the key of a value changing occasionally (and therefore the value being impossible to retrieve from the hash-table, since the binding is then in the wrong bucket), you can use the following low-level function as hash:

external address_of_value: 'a -> int = "address_of_value"

Implemented in C as:

#include "caml/mlvalues.h"

value address_of_value(value v)
{
  return (Val_long(((unsigned long)v)/sizeof(long)));
}

You would then use:

module H = Hashtbl.Make(struct
  type t = foo 
  let equal = (==) 
  let hash = address_of_value
end);;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文