在Matlab中创建一个哈希表的向量

5
我需要在Matlab中实现类似哈希表的功能,其中哈希表将向量映射到其他向量,向量数量(范围在数十万个)事先不确定。我尝试了Matlab内置的Containers.Map,但它不接受向量作为键。然后我尝试了java.util.HashMap:
>> map = java.util.HashMap;
>> map.put(1:3,zeros(2,1));
>> map.get(1:3)

 ans =

 []

因某种原因,这似乎行不通,尽管Java的HashMap应该能够将数组映射到数组。

另一种选择是保留两个单独的矩阵,一个用于键,一个用于值,并逐步增长它们。但我不想真的这样做,因为在Matlab中逐步增加东西很痛苦(即使使用块大小增量等,例如{{link1:here}})。

问题: 1. 为什么Java的HashMap在这里不起作用? 2. 有其他方法吗?

谢谢。


2
请查看https://dev59.com/FXM_5IYBdhLWcg3wgjW2。 - Rasman
1
键向量中的值范围是多少?如果它们是小于2^16的整数,您可以将它们转换为“char”,并使用生成的有趣字符串作为键。 - Andrew Janke
感谢大家的回答。关键向量确实是2^16以下的整数,因此我使用了带有char键的containers.Map和类似于Rasman链接中的键的java的HashMap进行比较:好吧,这里要发布太多代码了,所以我会将其作为答案发布。 - Matt
转念一想,你可以使用任何键向量值来完成这个任务,而不仅仅是小于2^16的整数,通过使用“typecast”将任意值的位模式放入字符中,例如“charKey = char(typecast(key,'uint16'))”。 - Andrew Janke
@Andrew:我错过了你的最后一条评论。由于某种原因,我没有收到电子邮件通知。类型转换是否会导致冲突?即两个不同的大于2^16的数字给出相同的类型转换? - Matt
@Matt:没有冲突,只要所有原始键都是相同类型的。类型转换与普通的Matlab类型转换不同。typecast不会进行四舍五入或扩展,它将精确保留底层位模式,只是将它们重新打包成新的数组类型。例如,如果您有一个double x,执行typecast(x,'uint16')将返回一个4个元素的uint16数组,其值看起来与x表示的数字完全不同。但这是一种无损转换。对于给定输入类型的任何两个不同数字,在类型转换后都会产生不同的结果。 - Andrew Janke
3个回答

4
这里有一个能够实现你想要的功能的折中方案......
map = java.util.HashMap;    
key = java.util.Vector;

matKey = 1:3;
for nn=1:numel(matKey)  
    key.add(matKey(nn));
end

map.put(key,zeros(2,1));
map.get(key)

无论如何,这是一个起点。


1
这可能可行,而且比“修补”更好,但你必须小心——通过在key中重用Java对象实例,有点作弊,因为我认为OP想要能够按值提取条目。 OP的代码不起作用,因为Matlab 1:3 被转换为具有身份相等语义的Java原始双精度数组。如果最终得到一个Double向量,则您的第一个示例将起作用,该向量将具有按值相等的语义。不确定转换会如何进行;您可能需要通过执行key.add(java.lang.Double(matKey(nn)));来强制执行它。 - Andrew Janke
1
第二个例子可能不起作用 - key.add(1:3) 最终会得到一个长度为一的 double[] 向量,这将以等同性结束。我认为您将无法使用不同的 1:3 将值取回;您需要原始的 key 对象。例如,如果您执行 key2 = java.util.Vector; key2.add(1:3); map.get(key2),它是否会检索到该值?因为我认为这是 OP 使其工作所需的。 - Andrew Janke
@AndrewJanke,你是正确的。经过测试,Kludge 2实际上并没有起作用。已删除。 - learnvst

1

我将 containers.Map 与 char 键(感谢 Andrew Janke)与使用包装对象作为键的 java.util.HashMap 进行了比较(如 this post 所示,同样感谢 Andrew Janke,并感谢 Rasman 指出):

numvec = 10^5;
S = round(rand(numvec,10)*40);

matmap = containers.Map();
%pick a random vector
idx = ceil(rand()*numvec);
s1 = S(idx,:);

%put it in the map
matmap(char(s1)) = zeros(1,4);
for i=1:5*10^5

  if i==10^3 tic; end %allow some time for getting up to speed before timing

  %pick a random vector and put it in the map
  idx = ceil(rand()*numvec);
  s2 = S(idx,:);
  matmap(char(s2)) = zeros(1,4);

  %retrieve value of previous vector
  v = matmap(char(s1));

  %modify it randomly and put it back
  v( ceil(rand()*4) ) = rand();
  matmap(char(s1)) = v;

  s1 = s2;
end
toc

javaaddpath('/Test/bin');
import test.ArrayKey;
javmap = java.util.HashMap;

idx = ceil(rand()*numvec);
s1 = S(idx,:);

%also convert value to ArrayKey so we can retrieve it by ref -- saves a put
%operation
javmap.put(ArrayKey(s1), ArrayKey(zeros(1,4)));
for i=1:5*10^5

  if i==10^3 tic; end

  idx = ceil(rand()*numvec);
  s2 = S(idx,:);
  javmap.put(ArrayKey(s2), ArrayKey(zeros(1,4)));
  v = javmap.get(ArrayKey(s1));
  v.x( ceil(rand()*4) ) = rand();
  s1 = s2;
end
toc

结果:

>> testmaps
Elapsed time is 58.600282 seconds.
Elapsed time is 97.617556 seconds.

containers.Map是胜者。


编辑:我重新运行了numvec = 10 ^ 6的测试,其他都相同。使用containers.Map方法运行时间为59秒。使用HashMap方法在5分钟后仍未完成,并导致Matlab无响应。


编辑2:我还尝试了预先分配两个矩阵并使用ismember查找键。性能比HashMap差。


很好。容器映射表的性能更高是有道理的:每个 M 代码中的 Java 调用都有开销,而键转换使用多个调用,随着键长度的增加而增加。 - Andrew Janke

0

最近我也遇到了一个类似的问题,不过不是关于向量而是数组。

Matlab有一个mat2str函数,可以将矩阵转换为字符串。如果你不需要哈希映射表中的向量动态增长,你可以将向量表示为字符串,并将其用作键/值。在某些情况下,这可能并不是很有用,但如果事情是静态的,那么这是一个快速而简单的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接