2012-10-09 50 views
5

Necesito una funcionalidad similar a hashmap en Matlab, donde el hashmap asigna vectores a otros vectores, y el número de vectores (que varían en cientos de miles) no se conoce de antemano.Creciendo un Hashmap de vectores en Matlab

Intenté el built-in de Matlab Containers.Map, pero eso no acepta vectores como claves. Luego probé java.util.HashMap:

>> map = java.util.HashMap; 
>> map.put(1:3,zeros(2,1)); 
>> map.get(1:3) 

ans = 

[] 

Así que por alguna razón que no parece funcionar, a pesar de que HashMap de Java debe ser capaz de asignar matrices de matrices.

La otra opción sería mantener dos matrices separadas, una para las claves y otra para los valores, y hacer que crezcan incrementalmente. Pero no quiero realmente hacer eso debido al dolor en Matlab de crecer incrementalmente (incluso con incrementos del tamaño de bloque, etc., por ejemplo, here).

Preguntas: 1. ¿Por qué no funciona el HashMap de Java aquí? 2. ¿Algún otro enfoque?

Gracias.

+2

echa un vistazo a http://stackoverflow.com/questions/1352553/how-can-i-use-matlab-arrays-as-keys-to-the-hashmap-java-objects – Rasman

+1

¿Cuál es el rango de valores en el vectores clave? Si tienen menos de 2^16, podrías convertirlos a 'char' y usar las cuerdas divertidas resultantes como claves. –

+0

Gracias a todos por sus respuestas. Los vectores clave son de hecho menos de 2^16, así que comparé el uso de contenedores.Mapa con las teclas de char y HashMap de Java con claves similares a la publicación a la que Rasman está vinculado: ok, es demasiado código para publicar aquí, así que lo publicaré como respuesta. – Matt

Respuesta

4

Aquí hay un kludge que hace lo que quiere. . .

map = java.util.HashMap;  
key = java.util.Vector; 

matKey = 1:3; 
for nn=1:numel(matKey) 
    key.add(matKey(nn)); 
end 

map.put(key,zeros(2,1)); 
map.get(key) 

..it es un punto de partida de todos modos.

+1

Esto podría funcionar, y ser mejor que un "kludge", pero hay que tener cuidado, está haciendo trampa un poco reutilizando la instancia del objeto Java en 'clave', cuando creo que OP quiere sacar entradas por valor. El código de OP no funciona porque el Matlab '1: 3' se convierte en una matriz doble primitiva de Java, que tiene una semántica de igualdad por identidad. Su primer ejemplo funcionará si termina con un Vector de Dobles, que tendrá una semántica de igualdad por valor. No estoy seguro de cómo irá la conversión; es posible que necesite forzarlo haciendo 'key.add (java.lang.Double (matKey (nn)));'. –

+1

Probablemente el segundo ejemplo no funcione: 'key.add (1: 3)' termina con un vector largo de doble [], que termina con igualdad por identidad. No creo que puedas volver a sacar el valor usando un '1: 3' diferente; necesitarías el objeto 'key' original. P.ej. si haces 'key2 = java.util.Vector; key2.add (1: 3); map.get (key2) ', ¿recupera el valor? Porque creo que eso es lo que OP necesitará para que funcione. –

+0

@AndrewJanke, estabas en lo cierto. Después de la prueba, Kludge 2 en realidad no funcionó. Se ha eliminado – learnvst

1

He comparado los contenedores.Mapa con las teclas de char (gracias a Andrew Janke) a java.util.HashMap con un objeto de envoltura como clave (como en this post, también gracias a Andrew Janke, y gracias a Rasman por señalarlo) :

numvec = 10^5; 
S = round(rand(numvec,10)*40); 

matmap = containers.Map(); 
%pick a random vector 
idx = ceil(rand()*numvec); 
s1 = S(idx,:); 

%put it in the map 
matmap(char(s1)) = zeros(1,4); 
for i=1:5*10^5 

    if i==10^3 tic; end %allow some time for getting up to speed before timing 

    %pick a random vector and put it in the map 
    idx = ceil(rand()*numvec); 
    s2 = S(idx,:); 
    matmap(char(s2)) = zeros(1,4); 

    %retrieve value of previous vector 
    v = matmap(char(s1)); 

    %modify it randomly and put it back 
    v(ceil(rand()*4)) = rand(); 
    matmap(char(s1)) = v; 

    s1 = s2; 
end 
toc 

javaaddpath('/Test/bin'); 
import test.ArrayKey; 
javmap = java.util.HashMap; 

idx = ceil(rand()*numvec); 
s1 = S(idx,:); 

%also convert value to ArrayKey so we can retrieve it by ref -- saves a put 
%operation 
javmap.put(ArrayKey(s1), ArrayKey(zeros(1,4))); 
for i=1:5*10^5 

    if i==10^3 tic; end 

    idx = ceil(rand()*numvec); 
    s2 = S(idx,:); 
    javmap.put(ArrayKey(s2), ArrayKey(zeros(1,4))); 
    v = javmap.get(ArrayKey(s1)); 
    v.x(ceil(rand()*4)) = rand(); 
    s1 = s2; 
end 
toc 

Resultado:

>> testmaps 
Elapsed time is 58.600282 seconds. 
Elapsed time is 97.617556 seconds. 

containers.Map es el ganador.


Editar: Volví a hacer la prueba de numvec = 10^6 y todo lo demás igual. El enfoque de los contenedores.Map se ejecutó en 59 segundos. El enfoque HashMap no finalizó después de 5 minutos y causó que Matlab dejara de responder.


Edit2: Yo también trató de pre-asignación de dos matrices separadas y encontrar claves utilizando ismember. El rendimiento fue peor que HashMap.

+0

Cool. Tiene sentido que los containers.Map superen: hay una sobrecarga para cada llamada de Java desde el código M, y la conversión de claves utiliza múltiples llamadas, aumentando con la longitud de la clave. –

0

Recientemente tuve que lidiar con un problema similar, no con vectores, sino con arreglos.

Matlab tiene una función función mat2str que convierte una matriz en una cadena. Si no necesita que los vectores crezcan dinámicamente en HashMap, puede representar el vector como una cadena y usarlo como su clave/valor. En algunas situaciones, esto probablemente no sea muy útil, pero es una solución rápida y sucia si las cosas son estáticas.