2011-04-20 28 views
14

Tengo Map<String, String> la clave String no es más que valor numérico como "123", etc. Obtengo valor numérico porque estos valores están llegando desde la interfaz de usuario en mi componente JSF. No quiero cambiar el contrato del componente UI.

Ahora me gustaría crear un Map<Long, String> basado en el Map anterior, vi algunos métodos transform en la clase Maps, pero todos se están centrando en el valor de conversión y no en la clave.

¿Hay alguna manera mejor de convertir Map<String, String> en Map<Long, String>?Cómo convertir Map <String, String> a Map <Long, String> usando guava

+0

No creo que haya una función incorporada para esto. Aunque no veo mucho uso para esto, es posible que desee [presentar una solicitud de función] (http://code.google.com/p/guava-libraries/issues/list). –

Respuesta

11

ACTUALIZACIÓN para Java 8

Usted puede utilizar flujos de hacer esto:

Map<Long, String> newMap = oldMap.entrySet().stream() 
    .collect(Collectors.toMap(e -> Long.parseLong(e.getKey()), Map.Entry::getValue)); 

Esto supone que todas las claves son válidos de cuerda representaciones de Long s. Además, puede tener colisiones cuando se transforma; por ejemplo, "0" y "00" ambos mapas a 0L.


Me gustaría pensar que tendría que iterar sobre el mapa:

Map<Long, String> newMap = new HashMap<Long, String>(); 
for(Map.Entry<String, String> entry : map.entrySet()) { 
    newMap.put(Long.parseLong(entry.getKey()), entry.getValue()); 
} 

Este código se supone que usted ha higienizado todos los valores en map (así que no hay valores largos no válidos).

Espero que haya una solución mejor.

EDITAR

me encontré con el método CollectionUtils#transformedCollection(Collection, Transformer) en Commons Colección-Utilidades de que parece que podría hacer lo que quiera. Scratch that, solo funciona para las clases que implementan Collection.

+0

sí ... ese sería el último enfoque;) – Premraj

+0

@Falcon :) Incluso si hubiera un método de transformación, la implementación interna tendría que ser algo similar. es decir, 'O (n)'. No puedo pensar en ninguna forma en que puedas hacer esto de modo que sea mejor que 'O (n)'. –

+2

No se trata de la complejidad, pero si algo ya está escrito o puede lograrse fácilmente con el enfoque funcional de guayaba (ya tengo la función escrita) y, por supuesto, con velocidad/eficiencia comparables, entonces no es necesario que haga esto. – Premraj

38

@ La respuesta de Vivin es correcta, pero creo que es útil explicar por qué Guava no tiene ningún método que le permita transformar las claves de un Map (o transformar un Set).

Todos los métodos de Guava para transformar y filtrar producen resultados flojos ... la función/predicado solo se aplica cuando es necesario a medida que se utiliza el objeto. Ellos no crean copias. Debido a eso, una transformación puede romper fácilmente los requisitos de Set.

Digamos, por ejemplo, que tiene un Map<String, String> que contiene "1" y "01" como claves. Ambos son distintos String s, por lo que el Map puede contener legalmente ambos como claves. Si los transforma utilizando Long.valueOf(String), ambos se correlacionan con el valor 1. Ya no son claves distintas. Esto no va a romper nada si crea una copia del mapa y agrega las entradas, porque cualquier clave duplicada sobrescribirá la entrada anterior para esa clave. Sin embargo, una transformada perezosamente Map no tendría forma de aplicar claves únicas y, por lo tanto, rompería el contrato de Map.

+0

perdón por eso, no vi la etiqueta de guayaba hasta más tarde: p –

2

La respuesta corta es no, la guayaba no la proporciona de la caja.

La manera simple sería algo como abajo. Sin embargo, hay algunas precauciones.

public static <K, V, L, W> Map<L, W> transformMap(Map<K, V> map, Function<K, L> keyFunction, Function<V, W> valueFunction) { 
    Map<L, W> transformedMap = newHashMap(); 

    for (Entry<K, V> entry : map.entrySet()) { 
     transformedMap.put(
       keyFunction.apply(entry.getKey()), 
       valueFunction.apply(entry.getValue())); 
    } 

    return transformedMap; 
} 

public static <K, V, L> Map<L, V> transformKeys(Map<K, V> map, Function<K, L> keyFunction) { 
    return transformMap(map, keyFunction, Functions.<V>identity()); 
} 

transformadores de guayaba son todos "perezosa" o basadas en vistas. Creo que para implementar un transformador de clave de mapa, querrías una función bidireccional. Entiendo que hay un Conversor en proceso por parte del equipo de Guava, que resolvería ese problema.

El otro problema con el que se encuentra es que tendría que lidiar con la posibilidad de duplicados para ser "Jimmy-proof", otro principio de Guava. Una forma de manejar eso sería devolver un Multimap; otro sería arrojar una excepción cuando encuentre duplicados. Lo que no recomendaría es ocultar el problema, p. ignorando las entradas subsiguientes con claves duplicadas, o sobrescribiendo la nueva entrada con la clave duplicada.

22

Ahora puede usar Java 8 stream, map, collect para hacer esto de una manera más legible y limpia.

Map<String, String> oldMap 

Map<Long, String> newMap = oldMap.entrySet().stream() 
    .collect(Collectors.toMap(entry -> Long.parseLong(entry.getKey()), Map.Entry::getValue)); 
3

Aquí es una versión actualizada de una de las respuestas siguientes para realizar el mapa resultante no se puede modificar (no, no está usando la guayaba, simplemente Java 8):

import static java.util.stream.Collectors.collectingAndThen; 
    import static java.util.stream.Collectors.toMap; 

    ... 

    newMap = oldMap.entrySet().stream().collect(collectingAndThen(
       toMap((Map.Entry<String, String> entry) -> transformKey(entry.getKey()), 
        (Map.Entry<String, String> entry) -> transformValue(entry.getValue())), 
       Collections::unmodifiableMap))); 
Cuestiones relacionadas