Question

Je voudrais appliquer une fonction à une collection Java, dans ce cas particulier une carte. Y at-il une belle façon de le faire? J'ai une carte et je voudrais juste équilibre courir () sur toutes les valeurs de la carte et afficher la carte reflètent les mises à jour.

Était-ce utile?

La solution

est avec les lambdas Java 8, une seule ligne:

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

Autres conseils

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 reprises si vous êtes manipuler ladite carte fortement.

Une méthode Collections2.transform(Collection<F>,Function<F,T>) similaire existe pour les collections.

Que vous pouvez modifier votre collection en place ou non dépend de la classe des objets de la collection.

Si ces objets sont immuables (qui sont des chaînes), alors vous ne pouvez pas prendre les éléments de la collection et les modifier - au lieu que vous devrez parcourir la collection, appelez la fonction correspondante, puis mettez le résultat valeur de retour.

Peut-être surpuissant pour quelque chose comme ça, mais il y a un certain nombre d'utilitaires très bons pour ces types de problèmes dans la section Jakarta Commons livre de recettes de O'Reilly.

J'ai fini à l'aide d'une mutation de la réponse de @ erickson, muté à:

  • retourner une nouvelle Collection, modifier pas en place
  • Collections de retour avec des éléments de type égal au type de retour de la Function
  • cartographie sur support, 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;
}

Vous devez itérer sur toutes les entrées et taillez chaque valeur de chaîne. Puisque chaîne est immuable, vous devrez re-mettre sur la carte. Une meilleure approche pourrait consister à réduire les valeurs comme ils sont placés dans la carte.

Je suis venu avec une classe "Mapper"

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 je l'utilise comme ça:

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

Vous pouvez également jeter un oeil à Collections Google

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top