Java collection / carte appliquer une méthode équivalente?
-
09-09-2019 - |
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.
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 -
Collection
s de retour avec des éléments de type égal au type de retour de laFunction
- 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