Как я могу использовать массивы MATLAB в качестве ключей к объектам Java HashMap?

Функция put работает нормально, но функция get не работает. Видимо, я не знаю трюка.

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

ans = []

Я искал и читал много сообщений, но не смог найти решение этой проблемы. Было бы здорово, если бы кто-нибудь мог сообщить мне трюк.

Ответ 1

Я думаю, проблема в том, что примитивные массивы Java не предоставляют для вас правильные equals() и hashCode(). Они используют стандартные методы Object, которые сравниваются с идентификатором объекта, а не с содержащимися значениями. При использовании нескалярных массивов в качестве ключей в HashMap Matlab преобразует их в double [], но они будут отличными объектами Java, поэтому они получат это поведение.

Если вы обернули ваши значения массива в объекте Java, который предоставил поведение по значению для equals() и hashCode(), прежде чем использовать их в качестве ключей, это может сработать. К счастью, 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 comparing by value, not Java object identity
key2 = EqualByValueDoubleArray(a);
gotBack = map.get(key2)

Это работает под R2008b для меня.

>> scratch_array_keyed_hashmap
gotBack =
my value

Для более простого использования вы можете создать подкласс HashMap, который проверил тип его входных ключей и автоматически обернул примитивные массивы в эту оберточную оболочку.

Ответ 2

Я не думаю, что вы можете использовать числовые векторы или матрицы как ключи в хэш-карте Java. Вместо этого вам придется преобразовать вектор или матрицу в один уникальный ключ, например, уникальное символьное строковое представление значений в векторе или матрице. Есть несколько способов сделать это:

  • Для целых массивов вы можете использовать функцию CHAR для преобразования целых чисел в их эквивалентные представления ASCII, создавая таким образом символьная строка. Это будет эффективно работать только для целочисленных значений от 0 до 65535, поскольку все, что находится за пределами этого диапазона, вероятно, будет иметь поведение undefined. Вот пример:

    X = [1 2 3; 4 5 6];  % X is a 2-by-3 matrix
    keyValue = char(X(:)');  % Reshape X to a row vector and convert to ASCII
    

    Для значений, слишком больших для использования CHAR, вы можете вместо INT2STR:

    keyValue = int2str(X(:)');
    
  • Для массивов с плавающей запятой вы можете использовать функцию NUM2STR для создания форматированного строкового представления каждого из элементы массива объединены вместе. Вот пример:

    X = rand(2,3)*9999;  % X is a 2-by-3 matrix of random double values
    keyValue = num2str(X(:)','%10.5f');
    

    Чтобы обеспечить уникальность ключа (избегая округления значения с плавающей запятой), вы могли вместо этого преобразовать двойные значения в свои полные 64-битные двоичные представления, используя DEC2BIN. Однако это, скорее всего, приведет к огромным символьным клавишам:

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

Один из недостатков этих опций заключается в том, что ваши ключи могут оказаться довольно длинными символьными строками. Я не уверен, есть ли верхний предел количества символов в ключе или если есть удар производительности при использовании длинных символьных строк для ключей.

Ответ 3

Структуры Matlab обеспечивают очень быстрый поиск из буквенно-цифровых клавиш (ну, [a-zA-Z] [a-zA-Z_0-9] * соответствие); в противном случае, если вы пытаетесь хешировать из чисел, я бы предложил использовать разреженные массивы с удвоением массива; пусть значение массива указывает на индекс во все, что вы пытаетесь найти. HTH

Ответ 4

Если вы используете более новую версию MATLAB (2008b или более поздней, я думаю), то у MATLAB есть свой собственный класс карты, который работает для определенных типов ключей. См. Документацию: container.Map