2011-09-30 11 views
9

Tengo un Hashmap que puede contener comodines (*) en la Cadena.Devolver una lista de coincidencias comodín de un HashMap en Java

Por ejemplo,

HashMap<String, Student> students_; 

puede tener a John * como una llave. Quiero saber si JohnSmith coincide con cualquier elemento en students_. Podría haber varias coincidencias para mi cadena (John *, Jo * Smith, etc.). ¿Hay alguna manera de que pueda obtener una lista de estas coincidencias de mi HashMap?

¿Hay algún otro objeto que podría estar usando que no requiera que itere a través de cada elemento de mi colección, o tengo que absorberlo y usar un objeto List?

FYI, mi colección tendrá menos de 200 elementos y, en última instancia, querré encontrar el par que coincida con la menor cantidad de comodines.

+2

funciones de hashing en general se construyen de manera que los cambios de menor importancia (por ejemplo: '' John SmitH' a John Smith') produce hashes totalmente diferentes. – NullUserException

+0

¿Por qué no quieres iterar? No es tan malo (especialmente con menos de 200 elementos) y, en última instancia, cualquier otra solución implicará algo similar en términos de rendimiento. – Guillaume

+0

Con menos de 200 elementos, simplemente realice la búsqueda lineal sobre 'entrySet()' y evalúe su comodín con cada tecla.Si hubiera sido mucho más, sugerí una base de datos (incrustada) y una consulta 'LIKE'. –

Respuesta

1

No se puede lograr con un hasmap, debido a la función hash. Tendría que asignar el hash de "John*" y el hash de "John Smith" y otros. el mismo valor

usted podría hacerlo con un TreeMap, si usted escribe su propia clase personalizada WildcardString cordón de envolver, y poner en práctica compareTo de tal manera que "John*".compareTo("John Smith") devuelve 0. Se puede hacer esto con expresiones regulares como other answers ya se han señalado.

Al ver que desea la lista de coincidencias de widlcard siempre puede eliminar las entradas tal como las encuentra e iterar TreeMap.get(). Recuerde volver a poner las llaves una vez que haya terminado con un nombre.

Esta es solo una forma posible de lograrlo. Con menos de 200 elementos estarás bien iterando.

ACTUALIZACIÓN: para imponer el orden correctamente en el TreeSet, se podía distinguir el caso de la comparación de dos WildcardString s (lo que significa que es una comparacion entre las teclas) y la comparación de un WildcardString a un String (comparando una clave con un valor de búsqueda) .

+0

Gracias, Xavi. Para una lista de 200, ¿cree que habrá algún beneficio de rendimiento al usar un TreeSet? – Sarah

+2

La creación de un método compareTo (cadena) en la clase WildCardString rompería el contrato del método compareTo porque: 'wildCardString.compareTo (string)' puede no ser el signo opuesto o 'string.compareTo (wildCardString)'. Además, se recomienda que compareTo sea coherente con iguales. – Jim

+0

@jim Gracias por su visión, buen punto. –

3

Puede usar regex para que coincida, pero primero debe convertir "John*" en equivalente en expresiones regulares "John.*", aunque puede hacerlo sobre la marcha.

Aquí hay un código que funcione:

String name = "John Smith"; // For example 
Map<String, Student> students_ = new HashMap<String, Sandbox.Student>(); 

for (Map.Entry<String, Student> entry : students_.entrySet()) { 
    // If the entry key is "John*", this code will match if name = "John Smith" 
    if (name.matches("^.*" + entry.getKey().replace("*", ".*") + ".*$")) { 
     // do something with the matching map entry 
     System.out.println("Student " + entry.getValue() + " matched " + entry.getKey()); 
    } 
} 
+1

Dijo específicamente que no quería repetir todas las entradas ... – Guillaume

+0

@Guillaume no lo hizo específicamente ** NO ** decir eso. Específicamente, dijo: * ¿Hay algún otro objeto que pueda estar usando que no requiera que itere a través de cada elemento en mi colección, ** o tengo que absorberlo y usar un objeto List **? *. Respondí la pregunta confirmando la parte * OR *. – Bohemian

+1

Bohemian, sofista :-) Estoy de acuerdo con tu respuesta de todos modos. No veo por qué no quiere iterar. – Guillaume

0

Usted puede simplemente repetir su mapa sin convertirlo en una lista, y el uso de la cadena coincide con la función, wih utiliza una expresión regular.

Si se quiere evitar el bucle, puede utilizar la guayaba como esto

@Test 
public void hashsetContainsWithWildcards() throws Exception { 
Set<String> students = new HashSet<String>(); 
students.add("John*"); 
students.add("Jo*Smith"); 
students.add("Bill"); 

Set<String> filteredStudents = Sets.filter(students, new Predicate<String>() { 
    public boolean apply(String string) { 
    return "JohnSmith".matches(string.replace("*", ".*")); 
    } 
}); 

assertEquals(2, filteredStudents.size()); 
assertTrue(filteredStudents.contains("John*")); 
assertTrue(filteredStudents.contains("Jo*Smith")); 

}

Cuestiones relacionadas