如何将MATLAB数组用作HashMap Java对象的键?

10

put函数可以正常工作,但get函数不行。显然我不知道诀窍。

>> X = [ 1, 2, 3];
>> M = java.util.HashMap;
>> M.put(X,1);
>> M.get([1,2,3])

ans = []

我搜索并阅读了很多帖子,但无法找到解决这个问题的方法。如果有人知道这个技巧,请告诉我。

4个回答

6
我认为问题在于Java原始数组没有为您提供正确的equals()和hashCode()。它们使用标准的Object方法进行比较,而不是包含的值。当在HashMap中使用非标量数组作为键时,Matlab将把它们转换为double [],但它们将是不同的Java对象,因此它们将获得这种行为。
如果您在使用它们作为键之前将数组值包装在提供按值行为的equals()和hashCode()的Java对象中,则可以实现此目标。幸运的是,java.util.Arrays为原始数组提供了按值实现。我们只需要将它们放入提供HashMap所需接口的包装类中即可。
package test;
import java.util.Arrays;

/**
 * A double[] that with by-value semantics for equals() and hashCode() so you
 * can use it in HashMaps.
 * In a non-toy class, you'd probably use switch statements to support arrays
 * of any primitive type. In a language with real generics, you'd just template
 * this.
 */
public class EqualByValueDoubleArray {
    private double[] x;
    public EqualByValueDoubleArray(double[] x) { this.x = x; }
    public double[] getArray() { return x; };
    public boolean equals(Object obj) {
        if (obj instanceof EqualByValueDoubleArray) {
            return Arrays.equals(this.x, ((EqualByValueDoubleArray)obj).x);
        } else {
            return false;
        }
    }
    public int hashCode() { return Arrays.hashCode(x); }
}

现在您可以将它们包装起来并将其用作Matlab中的键。
function scratch_array_keyed_hashmap
import test.EqualByValueDoubleArray;
map = java.util.HashMap;
a = [1 2 3 4 5]';

key = EqualByValueDoubleArray(a);
map.put(key, 'my value');
% Separate key so we know it's comparing by value, not Java object identity
key2 = EqualByValueDoubleArray(a);
gotBack = map.get(key2)

这对我来说在R2008b下有效。
>> scratch_array_keyed_hashmap
gotBack =
my value

为了更方便使用,您可以创建一个HashMap子类来检查其输入键的类型,并自动将原始数组包装在这个按值封装器中。


1

我认为你不能在Java哈希映射中使用数字向量或矩阵作为键。相反,你需要将向量或矩阵转换为单个唯一的键,例如向量或矩阵中值的唯一字符字符串表示。有几种方法可以做到这一点:

  • 对于整数数组,你可以使用CHAR函数将整数转换为它们相应的ASCII表示,从而创建一个字符串。这只对取值在0和65535之间的整数有效,因为超出该范围的值可能会导致未定义的行为。下面是一个例子:

    X = [1 2 3; 4 5 6];  % X是一个2行3列的矩阵
    keyValue = char(X(:)');  % 将X重新形状为行向量并转换为ASCII
    

    对于超过CHAR函数能处理的大整数,你可以使用INT2STR

    keyValue = int2str(X(:)');
    
  • 对于浮点数数组,你可以使用NUM2STR函数将每个数组元素的格式化字符串表示连接起来。下面是一个例子:

    X = rand(2,3)*9999;  % X是一个随机双精度值的2行3列矩阵
    keyValue = num2str(X(:)','%10.5f');
    

    为了确保键的唯一性(避免浮点值的舍入误差),你可以将双精度值转换为完整的64位二进制表示,使用DEC2BIN函数。然而,这可能会导致非常长的字符键:

    keyValue = reshape(dec2bin(X(:),64)',1,[]);
    

这些选项的一个缺点是,您的键可能最终变成相当长的字符字符串。我不确定键中字符数是否有上限,或者使用长字符字符串作为键是否会影响性能。


谢谢。这适用于整数输入。有没有办法将Matlab矩阵生成Java对象?(例如1:.1:3)char函数也可以在它们上面工作,但我认为它只是忽略了非整数部分。 - user165466
再次感谢。它运行得相当不错,尽管速度非常慢。我做这个的原因是尝试在Matlab中实现一个高效的A算法。因此,我正在使用Java对象进行快速访问,但似乎最好编写C++代码并将其转换为Mex文件。关键是,我希望A尽可能灵活。例如,接收所有搜索域规格作为输入函数。 - user165466

0

Matlab的结构体提供了非常快速的字母数字键查找(匹配[a-zA-Z][a-zA-Z_0-9] * ); 如果无法使用此方法,则如果您尝试从数字进行哈希,我建议使用稀疏数组和数组加倍; 让数组值指向您要查找的任何内容的索引。 hth


-1

如果您正在使用更高版本的MATLAB(2008b或更高版本),那么MATLAB有自己的映射类,适用于某些类型的键。请参阅文档:containers.Map


很遗憾,Matlab中的容器不支持矩阵。 - user165466

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