J'essaye de rassembler une liste dans une carte mais j'ai une entrée en double dans l'objet de liste.
Alors supposons que j'ai une aList
où j'ai
[{1, "abc.jpg"}, {2, "bcd.png"}, {1, "mno.jpg"}, {3, "abc.jpg"}, {1, null}, {1, ""}]
Maintenant, dans la liste ci-dessus, vous pouvez voir 1 a une valeur à la répétition avec des valeurs différentes.
Je souhaite rassembler la liste ci-dessus dans la carte fournie uniquement si elle a une certaine valeur.
comme dans l'ensemble ci-dessus, vous pouvez vous demander si je trouve distinct, puis collectez en les regroupant quelle valeur remplie sera choisie ma réponse est que toute valeur remplie est requise mais pas vide, espace ou nul.
donc tout le monde pourrait être d'accord sauf dans trois cas vide, espace blanc ou nul .
Je veux juste définir dans ma liste si cet identifiant a une image ou ne vérifie donc pas uniquement vide, espace ou null.
Sortie (ambiguë):
Sortie 1
[{1, "abc.jpg"}, {2, "bcd.png"}, {3, "abc.jpg"}]
Sortie 2
[{2, "bcd.png"}, {1, "mno.jpg"}, {3, "abc.jpg"}]
Les deux résultats de la liste ci-dessus pourraient être la sortie dans la carte.
Mon approche:
itemDetailsList.stream().filter(obj->itemImageMap.containsKey(obj.getItemUuid())).map(obj-> { String imageUrl = itemImageMap.get(obj.getItemUuid()); if(StringUtils.isNotBlank(imageUrl)) obj.setShowImage(true); return obj; });
J'obtiens une erreur de clé en double.
Pour plus de clarté sur ce que mon but est de collecter dans la carte. Une fois que je suis rassemblé sur la carte, mon objectif est le suivant =>
itemImageMap = imageService.findByItemUuidIn(itemUuids) .stream().filter(obj->(Objects.nonNull(obj)&& Objects.nonNull(obj[1]))) .collect(Collectors.toMap(obj->String.valueOf(obj[0]), obj->String.valueOf(obj[1])));
si j'ai un chemin, définissez true sinon la valeur par défaut est false.
4 Réponses :
Utilisez Collectors.groupingBy
utilisant la méthode getItemUuid()
avec les aval suivants:
Collectors.mapping
pour obtenir l'URL de l'image (je suppose qu'il existe une méthode MyObject#getUrl
).Collectors.filtering
pour filtrer les chaînes invalides à partir de java-9 et versions ultérieures, sinon vous devez utiliser le filter
avant d'entrer la méthode de collect
.Java 8
Map<Integer, List<String>> map = list.stream() .collect(Collectors.groupingBy(MyObject::getItemUuid, Collectors.mapping(MyObject::getUrl, Collectors.filtering(url -> url != null && !url.trim().isEmpty(), Collectors.toList()))));
Java 9+
Map<Integer, List<String>> map = list.stream() .filter(obj -> obj.getUrl() != null && !obj.getUrl().trim().isEmpty()) .collect(Collectors.groupingBy( MyObject::getItemUuid, Collectors.mapping(MyObject::getUrl, Collectors.toList())));
Résultat:
{1=[abc.jpg, mno.jpg], 2=[bcd.png], 3=[abc.jpg]}
Je n'ai pas de collectionneurs. Filtrage J'utilise java 8
Ah, mon erreur. Si vous attendez, j'inclurai un moyen Java 8 dans quelques heures :)
D'accord. J'attends
Jetez un œil à la réponse mise à jour.
ok donc la chose est que je veux collecter dans Map<String, String>
où Map<itemUuid, imageUrl>
si vous voyez ma sortie ... j'ai également dit qu'avec une seule clé, il ne devrait avoir qu'une valeur non multiple mais vous les avez matraqués valeurs .... @ abhijeet sarkar semble l'avoir très bien fait si vous regardez sa réponse
Comment décider si ce serait abc.jpg
ou mno.jpg
?
Je n'en ai pas besoin simplement pour mettre booléen s'il y a une image sinon false de sorte que lorsque l'utilisateur clique sur cette icône, il ouvrira un modal qui appellera mon api imageService qui apportera toutes les images référencées à cet élémentUuid en fait je ne le fais pas ' ne veut pas afficher modal s'il n'y a pas d'images
Si j'ai bien compris votre idée, voici ma réponse inspirée de cette réponse :
class Data { Integer id; String name; public Data(Integer id, String name) { this.id = id; this.name = name; } public Integer getId() { return id; } @Override public String toString() { return "Data{" + "id=" + id + ", name='" + name + '\'' + '}'; } } public class Main { public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) { Set<Object> seen = ConcurrentHashMap.newKeySet(); return t -> seen.add(keyExtractor.apply(t)); } public static void main(String[] args) { List<Data> list = List.of(new Data(1, "abc.jpg"), new Data(2, "bcd.png"), new Data(1, null)); List<Data> result = list.stream() .filter(d -> d.name != null && !d.name.equals("")) .filter(distinctByKey(Data::getId)) .collect(Collectors.toList()); result.forEach(System.out::println); }
}
cela fonctionnera-t-il si j'ai un doublon dans le premier filtre de cas, mais cela pourrait donner une exception dans le deuxième cas peut-être quand il ne pourrait pas déterminer une clé distincte ..... pouvez-vous exécuter en ajoutant un autre {1, "mno.jpg"}
Le JDK a une classe pour ce que vous appelez Data
- Map.Entry
.
@Kramer j'ai essayé avec `List <Data> list = List.of (new Data (1," abc.jpg "), new Data (2," bcd.png "), new Data (1, null), new Data (1, "mno.jpg"), nouvelles données (1, "mno.jpg")); `et cela a fonctionné. La clé est le "1", pas le name
l'image.
@AbhijitSarkar Vous n'êtes pas obligé d'utiliser cette classe si vous ne le souhaitez pas. La partie qui résout votre problème est le Predicate
.
Je n'ai pas de problème, c'est OP.
Pour supprimer l'erreur de clé en double, utilisez la version surchargée de toMap
avec un troisième paramètre indiquant la valeur à conserver en cas de duplication. Par exemple pour conserver la première valeur:
.collect(Collectors.groupingBy(obj->String.valueOf(obj[0]), Collectors.mapping(obj->String.valueOf(obj[1]), Collectors.toList())));
Mais en cas de doublons, au lieu d'ignorer une valeur, vous pouvez également utiliser vos clés pour regrouper les valeurs dans une liste afin d'obtenir une Map<String,List<String>
au lieu de Map<String,String>
. Quelque chose comme:
.collect(Collectors.toMap(obj->String.valueOf(obj[0]), obj->String.valueOf(obj[1]), (first, second) -> first));
var list = List.<Map.Entry<Integer, String>>of( new AbstractMap.SimpleImmutableEntry<>(1, "abc.jpg"), new AbstractMap.SimpleImmutableEntry<>(2, "bcd.png"), new AbstractMap.SimpleImmutableEntry<>(1, "mno.jpg"), new AbstractMap.SimpleImmutableEntry<>(3, "abc.jpg"), new AbstractMap.SimpleImmutableEntry<>(1, null), new AbstractMap.SimpleImmutableEntry<>(1, "") ); var map = list.stream() .filter(it -> it.getValue() != null && !it.getValue().isEmpty()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1)); System.out.println(map); {1=abc.jpg, 2=bcd.png, 3=abc.jpg} I used Java 11 var and List.of, but the code could easily be adapted to Java 8. Java is so dang verbose, new AbstractMap.SimpleImmutableEntry<>(1, "abc.jpg") gives me headache every time I want to create a pair.
Ce serait tellement plus facile de vous aider si, au lieu de la longue lecture, vous venez de fournir une entrée (comme vous l'avez fait) et une sortie attendue.
@MaksymRudenko a ajouté le résultat attendu car la sortie est ambiguë donc les deux résultats possibles sont présentés