2009-04-13 6 views
24

Je voudrais appliquer une fonction à une collection Java, dans ce cas particulier une carte. Y a-t-il une bonne façon de faire ça? J'ai une carte et je voudrais simplement exécuter trim() sur toutes les valeurs de la carte et faire en sorte que la carte reflète les mises à jour.Collection Java/carte méthode d'application équivalente?

Répondre

36

Avec les lambdas Java 8, ceci est une doublure:

map.replaceAll((k, v) -> v.trim()); 

Pour l'amour de l'histoire, voici une version sans lambdas:

public void trimValues(Map<?, String> map) { 
    for (Map.Entry<?, String> e : map.entrySet()) { 
    String val = e.getValue(); 
    if (val != null) 
     e.setValue(val.trim()); 
    } 
} 

Ou, plus généralement:

interface Function<T> { 
    T operate(T val); 
} 

public static <T> void replaceValues(Map<?, T> map, Function<T> f) 
{ 
    for (Map.Entry<?, T> e : map.entrySet()) 
    e.setValue(f.operate(e.getValue())); 
} 

Util.replaceValues(myMap, new Function<String>() { 
    public String operate(String val) 
    { 
    return (val == null) ? null : val.trim(); 
    } 
}); 
+1

+1 pour le modèle lambda fonction – Alnitak

+0

Hey erickson - où puis-je en savoir plus sur cette syntaxe: Carte carte ?? J'apprends juste Java et n'ai pas rencontré quelque chose comme ça .. n'importe quelle direction serait appréciée! –

+2

@jamesemanon Cela signifie que la carte que vous passez à cette méthode peut avoir n'importe quel type de clé, mais la valeur doit être 'String'. Vous pouvez obtenir les notions de base à partir de [Java Tutorial] (https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html). [FAQ générique d'Angelika Langer] (http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html) contient des informations beaucoup plus détaillées sur tous les aspects de Java Generics. – erickson

2

Si vous pouvez modifier votre collection sur place ou non dépend de la classe des objets de la collection. Si ces objets sont immuables (ce que sont les chaînes), vous ne pouvez pas simplement prendre les éléments de la collection et les modifier. Au lieu de cela, vous devez parcourir la collection, appeler la fonction appropriée, puis mettre le valeur résultante en retour.

1

Vous devrez parcourir toutes les entrées et rogner chaque valeur de chaîne. Puisque String est immuable, vous devrez le réinscrire dans la carte. Une meilleure approche pourrait être d'ajuster les valeurs lorsqu'elles sont placées sur la carte.

2

Peut-être trop pour quelque chose comme ceci, mais il y a un certain nombre de très bons utilitaires pour ces types de problèmes dans la bibliothèque Apache Commons Collections.

Map<String, String> map = new HashMap<String, String>(); 
map.put("key1", "a "); 
map.put("key2", " b "); 
map.put("key3", " c"); 

TransformedMap.decorateTransform(map, 
    TransformerUtils.nopTransformer(), 
    TransformerUtils.invokerTransformer("trim")); 

Je recommande vivement le Jakarta Commons Cookbook de O'Reilly.

+1

Je voulais juste mentionner la version immuable dans la bibliothèque Apache Commons Collections: CollectionUtils.collect (Collection inputCollection, transformateur Transformer) – Jakub

-1

Vous pouvez également jeter un oeil à Google Collections

+2

Type de vague ... au moins fournir un lien et une description/exemple de la façon d'utiliser Google Collections pour résoudre le problème? –

11

Je ne sais pas une façon de faire avec les bibliothèques autre que votre JDK réponse acceptée, mais Google Collections vous permet de faire la chose suivante, avec les classes com.google.collect.Maps et com.google.common.base.Function:

Map<?,String> trimmedMap = Maps.transformValues(untrimmedMap, new Function<String, String>() { 
    public String apply(String from) { 
    if (from != null) 
     return from.trim(); 
    return null; 
    } 
} 

la plus grande différence de cette méthode avec celle proposée est qu'il offre une vue sur votre carte originale, ce qui signifie que, alors qu'il est toujours en phase avec votre carte originale, la méthode apply pourrait être invoqué plusieurs fois si vous manipulez sai d carte fortement. Une méthode Collections2.transform(Collection<F>,Function<F,T>) similaire existe pour les collections.

1

Je suis venu avec un "Mapper" classe

public static abstract class Mapper<FromClass, ToClass> { 

    private Collection<FromClass> source; 

    // Mapping methods 
    public abstract ToClass map(FromClass source); 

    // Constructors 
    public Mapper(Collection<FromClass> source) { 
     this.source = source; 
    } 
    public Mapper(FromClass ... source) { 
     this.source = Arrays.asList(source); 
    } 

    // Apply map on every item 
    public Collection<ToClass> apply() { 
     ArrayList<ToClass> result = new ArrayList<ToClass>(); 
     for (FromClass item : this.source) { 
      result.add(this.map(item)); 
     } 
     return result; 
    } 
} 

que j'utilise comme ça:

Collection<Loader> loaders = new Mapper<File, Loader>(files) { 
    @Override public Loader map(File source) { 
     return new Loader(source); 
    }   
}.apply(); 
2

je me suis retrouvé à l'aide d'une mutation de la réponse de @ erickson, muté à:

  • retourner une nouvelle Collection, ne pas modifier en place
  • retourner Collection s avec des éléments de type égal au type de retour de la carte de support Function
  • sur soit les valeurs d'une carte ou les éléments d'une liste

code:

public static interface Function<L, R> { 
    L operate(R val); 
} 

public static <K, L, R> Map<K, L> map(Map<K, R> map, Function<L, R> f) { 
    Map<K, L> retMap = new HashMap<K, L>(); 

    for (Map.Entry<K, R> e : map.entrySet()) retMap.put(e.getKey(), f.operate(e.getValue())); 

    return retMap; 
} 

public static <L, R> List<L> map(List<R> list, Function<L, R> f) { 
    List<L> retList = new ArrayList<L>(); 

    for (R e : list) retList.add(f.operate(e)); 

    return retList; 
} 
Questions connexes