Data structures 什么';序列的最紧凑表示是什么?
我正在存储一个映射,我有Data structures 什么';序列的最紧凑表示是什么?,data-structures,clojure,Data Structures,Clojure,我正在存储一个映射,我有seqs个整数作为键。hashmap相当大(100000个键),因此我希望使用最紧凑的存储方法来节省RAM 有几个选项,包括ClojureLazySeqs、vectors、java.util.array甚至字符串。我不需要上述的懒惰、坚持或内敛,只需要将它们用作不透明的键 这类数据有已知的最小表示吗 编辑因为问题不清楚,我想使用hashmap,因为它提供了一些功能。我不想要另一种抽象数据类型。我对最小化钥匙的尺寸感兴趣 这实际上取决于您需要对这些数据执行的操作。最常见的解
seq
s个整数作为键。hashmap相当大(100000个键),因此我希望使用最紧凑的存储方法来节省RAM
有几个选项,包括ClojureLazySeq
s、vectors、java.util.array
甚至字符串。我不需要上述的懒惰、坚持或内敛,只需要将它们用作不透明的键
这类数据有已知的最小表示吗
编辑因为问题不清楚,我想使用hashmap,因为它提供了一些功能。我不想要另一种抽象数据类型。我对最小化钥匙的尺寸感兴趣 这实际上取决于您需要对这些数据执行的操作。最常见的解决方案是[[set,value],…],尽管它在ram方面不会比hashmap好多少。可能是时候转移到外部K/V了?如前所述,这实际上取决于您需要对数据执行的操作 例如,如果您不介意一定程度的误报(但没有误报),您可以使用,或者,如果键是静态的,您可以使用,您可以使用访问,例如,数组或文件 更新
bloom过滤器确实用于表示集合,而不是映射。然而,我发现一篇有趣的论文概括了这一点。但是还没有找到它的任何实现。如果内存优化很重要,您可能需要使用int(或long)的Java本机数组。但是,您需要定义一个包装类,以便实现正确的
equals
和hashcode
契约,因为Java本机数组是对象,但只是从对象继承equals
和hashcode
。
我还没有做过任何测量,但是——取决于密钥序列中int的数量——并且知道不可变Clojure向量背后的数据结构,这可能会产生重大影响
为此,您可以使用java.lang.Arrays
中的实用程序函数,并在java中定义一个简单的包装器:
public final class IntKey {
private final int[] data;
public IntKey(int[] data) {
if (data == null) {
throw new NullPointerException();
}
this.data = data;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof IntKey)) {
return false;
}
return Arrays.equals(data, ((IntKey)other).data);
}
@Override
public int hashCode() {
return Arrays.hashCode(data);
}
}
或者在Clojure中使用deftype
:
(deftype IntKey [^ints data]
java.lang.Object
(equals [this other]
(java.util.Arrays/equals data (.data other)))
(hashCode [this]
(java.util.Arrays/hashCode data)))
然后测试本机数组不是好键:
(def k1 (int-array [1 2 3]))
(def k2 (int-array [4 5 6]))
(def k3 (int-array [1 2 3])) ;; same sequence as k1
(def h (hash-map ik1 "hello" ik2 "good" ik3 "bye"))
user> (map h [ik1 ik2 ik3])
user> ("hello" "good" "bye") ;; argh ik1 and ik3 should yield the same value
将int数组包装在IntKey
中并重新定义映射:
(def ik1 (IntKey. k1))
(def ik2 (IntKey. k2))
(def ik3 (IntKey. k3))
(def h (hash-map ik1 "hello" ik2 "good" ik3 "bye"))
user> (map h [ik1 ik2 ik3])
("bye" "good" "bye") ;; ok
user> (count h)
2
注意:您可能希望在包装器类中“缓存”hashcode值,以便每个序列只计算一次。您是否建议将整个结构存储为向量?若然,原因为何?它没有提供hashmap的任何功能(查找、唯一键),称为tuplelist。无论如何,你只是想找到最有效的钥匙存储?在这种情况下,向量是最好的候选者。这些是任意的整数序列,或者有任何约束,比如最小/最大长度或者可以用来压缩它们的值吗?如果你想到像RLE这样的东西,它们是不可能压缩的。它们大约有5位数长,显然每个序列都是唯一的。我使用hashmap是因为我想要它的所有功能!具体来说,存储任意(多个)值、检索、,更新等。我不确定你所说的静态键是什么意思-当然所有哈希表键都必须是不可变的?bloom过滤器不是用来表示集合而不是映射吗?我认为在这个上下文中“静态”意味着在应用程序的生命周期内不会向映射添加键或从映射中删除键。如果可以保证给定密钥集的哈希函数没有重复项,那么可以将哈希直接存储在映射中。啊,对了!不,我认为这不适用,但这是一个有趣的想法。就内存而言,这可能是最有效的,但你必须非常小心,一旦数组被添加为键,就不要改变数组的内容,否则查找将被破坏。一般来说,hashmaps中的可变键会带来麻烦。是的,我没有提到它,但在这个设计中,键应该是不可变的。谢谢。我刚刚找到了
的向量,它看起来非常相似。