【问题标题】:Growing a Hashmap of vectors in Matlab在 Matlab 中生成向量的 Hashmap
【发布时间】:2012-10-09 17:43:25
【问题描述】:

我需要 Matlab 中的类似 hashmap 的功能,其中 hashmap 将向量映射到其他向量,而向量的数量(范围为数十万)是事先不知道的。

我尝试了 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 中增量增长的痛苦(即使是块大小增量等,例如here)。

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

谢谢。

【问题讨论】:

  • 键向量中的值的范围是多少?如果它们是 2^16 以下的整数,您可以将它们转换为 char 并将生成的有趣字符串用作键。
  • 感谢大家的回答。键向量确实是 2^16 以下的整数,所以我比较了使用带有 char 键的 container.Map 和 java 的 HashMap,其键类似于 Rasman 链接到的帖子:好的,这里发布的代码太多,所以我将其作为答案发布.
  • 再想一想,您可以使用任何关键向量值来执行此操作,而不仅仅是 ints typecast 在字符中粘贴任意值的位模式,例如 charKey = char(typecast(key, 'uint16'))
  • @Andrew:我错过了你的最后一条评论。出于某种原因,我没有收到电子邮件通知。 {typecast} 不能导致冲突吗? IE。两个不同的数字 > 2^16 给出相同的类型转换?

标签: java matlab hashmap hashtable


【解决方案1】:

这是一个可以做你想做的事情。 . .

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)

..无论如何这都是一个起点。

【讨论】:

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

我比较了带有字符键的containers.Map(感谢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 的测试,其他一切都相同。 container.Map 方法在 59 秒内运行。 HashMap 方法在 5 分钟后未完成,导致 Matlab 无响应。


Edit2:我还尝试使用ismember 预先分配两个单独的矩阵并查找键。性能比 HashMap 差。

【讨论】:

  • 酷。有道理,containers.Map 的表现优于:M 代码的每个 Java 调用都有开销,并且密钥转换使用多次调用,随着密钥长度的增加而增加。
【解决方案3】:

我最近不得不处理一个类似的问题,不是向量而是数组。

Matlab 有一个函数 mat2str 函数,可以将矩阵转换为字符串。如果您不需要向量在 HashMap 中动态增长,则可以将向量表示为字符串并将其用作键/值。在某些情况下,这可能不是很有帮助,但如果事情是静态的,这是一个快速而肮脏的解决方案。

【讨论】:

    猜你喜欢
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多