Как я могу использовать массивы MATLAB в качестве ключей для Java-объектов HashMap? - PullRequest
10 голосов
/ 30 августа 2009

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

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

ans = []

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

Ответы [ 4 ]

6 голосов
/ 31 августа 2009

Я думаю, что проблема в том, что примитивные массивы 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'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 голос
/ 30 августа 2009

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

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

    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,[]);
    

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

0 голосов
/ 31 августа 2009

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

0 голосов
/ 30 августа 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...