web-dev-qa-db-fra.com

itération et filtrage de deux listes à l'aide de Java 8

Je veux parcourir deux listes et obtenir une nouvelle liste filtrée qui aura des valeurs non présentes dans la deuxième liste. Quelqu'un peut-il aider?

J'ai deux listes - une liste de chaînes et l'autre liste d'objets MyClass.

List<String> list1;
List<MyClass> list2;

MyClass {

    MyClass(String val)
    {
        this.str = val;
    }

     String str;
     ...
     ...
}

Je veux une liste filtrée de chaînes basée sur -> vérifier la deuxième liste d'éléments (abc) dont les valeurs ne sont pas présentes dans list1.

List<String> list1 = Arrays.asList("abc", "xyz", "lmn");

List<MyClass> list2 = new ArrayList<MyClass>();

MyClass obj = new MyClass("abc");
list2.add(obj);
obj = new MyClass("xyz");
list2.add(obj);

Maintenant, je veux une nouvelle liste filtrée -> qui aura valeur => "lmn". c'est-à-dire des valeurs non présentes dans list2 dont les éléments sont dans list1.

9
Arun Khot

Enfin, j’ai trouvé le moyen de parvenir à ce résultat suivant - 

List<String> unavailable = list1.stream()
                .filter(e -> (list2.stream()
                        .filter(d -> d.getStr().equals(e))
                        .count())<1)
                        .collect(Collectors.toList());

Mais cela fonctionne aussi comme prévu. S'il vous plaît laissez-moi savoir combien cela est efficace? et si quelqu'un a un autre moyen de faire la même chose?

3
Arun Khot
// produce the filter set by streaming the items from list 2
// assume list2 has elements of type MyClass where getStr gets the
// string that might appear in list1
Set<String> unavailableItems = list2.stream()
    .map(MyClass::getStr)
    .collect(Collectors.toSet());

// stream the list and use the set to filter it
List<String> unavailable = list1.stream()
            .filter(e -> unavailableItems.contains(e))
            .collect(Collectors.toList());
15
Ashley Frieze

Le faire avec des flux est facile et lisible:

Predicate<String> notIn2 = s -> ! list2.stream().anyMatch(mc -> s.equals(mc.str));
List<String> list3 = list1.stream().filter(notIn2).collect(Collectors.toList());
6
DSchmidt

Voir ci-dessous, nous aimerions recevoir vos commentaires sur le code ci-dessous. 

pas commun entre deux tableaux:

List<String> l3 =list1.stream().filter(x -> !list2.contains(x)).collect(Collectors.toList());

Commun entre deux tableaux:

List<String> l3 =list1.stream().filter(x -> list2.contains(x)).collect(Collectors.toList());
2
tosi

Une approche simple est une foreach dans list1 et vérifie si l'élément est dans la list2, sinon ajouter à list3.

outer:
for(String s : list1) {
    for(MyClass c : list2) 
        if(c.getStr().equals(s))
            continue outer;
    filteredList.add(c);
}

Si vous continuez à confondre l'étiquette, extrayez la boucle interne dans une fonction de renvoi booléen. Vous pouvez également remplacer le foreach classique pour l'itérateur de flux lambda.

public static boolean isInList(ArrayList<MyClass> list, String s) {
    list2.stream().foreach((o)-> {
        if(o.getStr().equals(s)) {
            return true;
        }
    });
    return false;
}

list1.stream().foreach((s) -> {
    if(!isInList(list2, s)) {
        list3.add(s);
    }
});

mais cela semble vraiment beaucoup plus compliqué/pollué et inutile à mes yeux.

De plus, String str dans votre classe n'a pas de définition publique, c'est pourquoi, dans les deux exemples, j'ai utilisé la méthode "getStr ()", en supposant que votre classe respecte le modèle de bean Java et contient une méthode getStr ().

2
Felype

Si vous diffusez la première liste et utilisez un filtre basé sur contient dans la seconde ...

list1.stream()
    .filter(item -> !list2.contains(item))

La question suivante concerne le code que vous ajouterez à la fin de cette opération de diffusion en continu pour traiter plus avant les résultats ... vers vous.

De plus, list.contains est assez lent, vous seriez donc mieux avec les ensembles.

Mais si vous utilisez des ensembles, vous trouverez peut-être des opérations plus simples, comme removeAll.

Set list1 = ...;
Set list2 = ...;
Set target = new Set();
target.addAll(list1);
target.removeAll(list2);

Étant donné que nous ne savons pas comment vous allez utiliser cela, il n’est pas vraiment possible de conseiller quelle approche adopter.

2
Ashley Frieze
list1 = list1.stream().filter(str1-> 
        list2.stream().map(x->x.getStr()).collect(Collectors.toSet())
        .contains(str1)).collect(Collectors.toList());

Cela peut fonctionner plus efficacement.

1
YiFu.Zhou

si vous avez la classe avec id et que vous voulez filtrer par id 

line1: vous mappez tous les identifiants

line2: filtre ce qui n'existe pas dans la carte 

Set<String> mapId = entityResponse.getEntities().stream().map(Entity::getId).collect(Collectors.toSet());

List<String> entityNotExist = entityValues.stream().filter(n -> !mapId.contains(n.getId())).map(DTOEntity::getId).collect(Collectors.toList());
0
Ran Adler