Как я могу использовать массивы 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