2009-08-29 19 views

risposta

6

Penso che il problema sia che gli array primitivi di Java non forniscono gli equals() e hashCode() corretti per voi. Usano i metodi Object standard che confrontano per identità oggetto invece di valori contenuti. Quando si usano gli array non scalari come chiavi in ​​una HashMap, Matlab li converte in double [], ma saranno oggetti Java distinti, quindi otterranno questo comportamento.

Se i valori dell'array sono stati racchiusi in un oggetto Java che fornisce un comportamento in base al valore per equals() e hashCode() prima di utilizzarli come chiavi, ciò potrebbe funzionare. Fortunatamente, java.util.Arrays fornisce implementazioni di valore per gli array primitivi. Abbiamo solo bisogno di schiaffarli in una classe wrapper che fornisce l'interfaccia che HashMap sta aspettando.

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); } 
} 

Ora puoi avvolgerli e usarli come chiavi da 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) 

Questo funziona per R2008b per me.

>> scratch_array_keyed_hashmap 
gotBack = 
my value 

Per un uso più semplice, è possibile creare una sottoclasse HashMap che controllato il tipo dei suoi tasti di ingresso, ed automaticamente avvolto array primitive in questo involucro per valore.

+0

Grazie mille. Funziona perfettamente! –

1

Non penso che sia possibile utilizzare i vettori numerici o le matrici come chiavi in ​​una hashmap Java. Dovresti invece convertire il vettore o la matrice in un'unica chiave univoca, ad esempio una rappresentazione di stringa di caratteri univoca dei valori nel vettore o nella matrice. Ci sono alcuni modi per farlo:

  • Per gli array di interi, è possibile utilizzare la funzione di CHAR per convertire i numeri interi per le loro rappresentazioni ASCII equivalenti, creando così una stringa di caratteri. Ciò funzionerà in modo efficace solo con valori interi compresi tra 0 e 65535, poiché qualsiasi elemento esterno a questo intervallo avrà probabilmente un comportamento non definito. Ecco un esempio:

    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 
    

    Per valori interi troppo grande per usare CAR, è possibile utilizzare INT2STR invece:

    keyValue = int2str(X(:)'); 
    
  • Per gli array in virgola mobile, è possibile utilizzare la funzione di NUM2STR per creare un formattato rappresentazione di stringa di ciascuno degli elementi dell'array concatenati insieme. Ecco un esempio:

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

    per garantire l'univocità della chiave (evitando arrotondamento del valore a virgola mobile) si potrebbe invece convertire i valori doppi alla loro completa rappresentazione binaria a 64 bit utilizzando DEC2BIN. Tuttavia, questo probabilmente porterà a enormi chiavi caratteri:

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

Uno svantaggio di queste opzioni è che le chiavi potrebbero potenzialmente finire per essere stringhe di caratteri piuttosto lunghi. Non sono sicuro se c'è un limite superiore al numero di caratteri nella chiave o se c'è un colpo di prestazioni nell'uso di stringhe di caratteri lunghi per le chiavi.

+0

grazie. Funziona per ingressi interi. Esiste comunque la possibilità di generare oggetti java con matrici Matlab? (ad esempio 1: .1: 3) La funzione char funziona anche su di essi, ma penso che ignori semplicemente le parti non interi. –

+0

Grazie ancora. Funziona piuttosto bene, anche se è molto lento. Il motivo per cui ho finito per farlo è che sto cercando di implementare un efficiente algoritmo A * in MATLAB. Quindi sto usando oggetti java per un accesso veloce ma sembra che sia meglio scrivere un codice C++ e messinizzarlo. Il problema è che mi piacerebbe avere A * il più flessibile possibile. Ad esempio, ricevendo tutte le specifiche del dominio di ricerca come funzioni di input. –

-1

Se si utilizza una versione più recente di MATLAB (2008b o versione successiva, penso), MATLAB ha una propria classe di mappa che funziona per determinati tipi di chiavi. Vedere la documentazione: containers.Map

+0

Sfortunatamente i contenitori in Matlab non supportano le matrici. –

0

Le strutture Matlab forniscono una ricerca molto veloce da chiavi alfanumeriche (beh, [a-zA-Z] [a-zA-Z_0-9] * matching); in caso contrario, se si sta tentando di eseguire l'hash dai numeri, suggerirei di utilizzare array sparsi con raddoppiamento degli array; lascia che l'arrayvalue punti all'indice in qualunque cosa tu stia cercando di cercare. h.

Problemi correlati