web-dev-qa-db-fra.com

Comparez deux listes via une propriété à l'aide de LINQ

Dites que j'ai ce qui suit:

    class Widget1{
        public int TypeID { get; set; }
        public string Color { get; set; }
    }

    class Widget2
    {
        public int TypeID { get; set; }
        public string Brand { get; set; }
    }

    private void test()
    {
        List<Widget1> widgets1 = new List<Widget1>();
        List<Widget2> widgets2 = new List<Widget2>();
        List<Widget1> widgets1_in_widgets2 = new List<Widget1>();

        //some code here to populate widgets1 and widgets2

        foreach (Widget1 w1 in widgets1)
        {
            foreach (Widget2 w2 in widgets2)
            {
                if (w1.TypeID == w2.TypeID)
                {
                    widgets1_in_widgets2.Add(w1);
                }
            }
        }
    }

J'utilise deux boucles foreach pour comparer les listes par TypeID afin de remplir une troisième liste. Existe-t-il un autre moyen d’utiliser LINQ pour comparer ces deux listes via le TypeID? Peut-être en utilisant Interstect ou une autre fonction?

41
Coltech

Ce que vous voulez ici est un Join.

var widgets1_in_widgets2 = from first in widgest1
    join second in widgets2
    on first.TypeID equals second.TypeID
    select first;

Intersect peut être plus ou moins considéré comme un cas spécial de Join où les deux séquences sont du même type, et peut donc être appliqué pour l'égalité au lieu d'avoir besoin d'une projection pour chaque type générer une clé pour comparer. Compte tenu de votre cas, Intersect n'est pas une option.

Si un ID particulier est dupliqué dans votre deuxième ensemble et que vous ne voulez pas que l'élément soit dupliqué dans les résultats, vous pouvez utiliser un GroupJoin au lieu d'un Join:

var widgets1_in_widgets2 = from first in widgest1
    join second in widgets2
    on first.TypeID equals second.TypeID
    into matches
    where matches.Any()
    select first;
39
Servy

Tu peux le faire

widgets2.Where(y=>widget1.Any(z=>z.TypeID==y.TypeID));
39
Anirudha

Join a l'inconvénient que vos résultats peuvent être dupliqués si widgets1 ou widgets2 contient plusieurs éléments avec le même TypeID (ce qui s'applique également à votre code d'origine, d'ailleurs).

Ce qui suit fera exactement ce que vous voulez: Renvoyer tous les éléments de widgets1 pour lesquels un élément avec un TypeID correspondant existe dans widgets2.

widgets1_in_widgets2 = (from w1 in widgets1
                        where widgets2.Any(w2 => w1.TypeID == w2.TypeID)
                        select w1).ToList()
4
Heinzi

J'aime cette solution car elle est simple à lire dans le code.

bool result = firstList.All(o => secondList.Any(w => w.Prop1 == o.Prop1 && w.Prop2 == o.Prop2));

Voir l'exemple complet dans le violon: exemple de comparaison au violon

2
Bruno Gozzi

Essayez d'utiliser la surcharge de "Où"

var isMatch = !widgets1.Where((w1, index) => w1.TypeId == widgets2[index].TypeId)).Any();
2
Soumya Das