0
votes

La carte collecte des valeurs distinctes sous condition

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.


2 commentaires

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


4 Réponses :


1
votes

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 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]}


7 commentaires

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>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



0
votes

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

}


5 commentaires

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.



2
votes

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


0 commentaires

2
votes
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.

0 commentaires