Sprawdź, czy lista <t> zawiera inną listę


103

Mam listę parametrów takich jak ta:

public class parameter
{
    public string name {get; set;}
    public string paramtype {get; set;}
    public string source {get; set;}
}

IEnumerable<Parameter> parameters;

I tablicę ciągów, z którymi chcę to porównać.

string[] myStrings = new string[] { "one", "two"};

Chcę iterować listę parametrów i sprawdzić, czy właściwość source jest równa dowolnej z tablicy myStrings. Mogę to zrobić z zagnieżdżonymi foreach, ale chciałbym nauczyć się, jak to zrobić w przyjemniejszy sposób, ponieważ bawiłem się linq i podobały mi się metody rozszerzające na wyliczalnych, takich jak gdzie itp., Więc zagnieżdżone foreach po prostu czują się źle. Czy istnieje bardziej elegancki preferowany sposób linq / lambda / delegete?

Dzięki

Odpowiedzi:


220

Możesz użyć zagnieżdżonego Any()do tego sprawdzenia, które jest dostępne na Enumerable:

bool hasMatch = myStrings.Any(x => parameters.Any(y => y.source == x));

Szybsze wykonanie na większych kolekcjach byłoby rzutowaniem parametersna, sourcea następnie użycie, Intersectktóre wewnętrznie używa a HashSet<T>so zamiast O (n ^ 2) dla pierwszego podejścia (odpowiednik dwóch zagnieżdżonych pętli), możesz wykonać sprawdzenie w O (n):

bool hasMatch = parameters.Select(x => x.source)
                          .Intersect(myStrings)
                          .Any(); 

Jako komentarz boczny należy również użyć wielkich liter w nazwach klas i nazwach właściwości, aby były zgodne z wytycznymi dotyczącymi stylu języka C #.


dzięki wydaje mi się, czego szukam, spróbuję tego. Trzeba trochę więcej pobawić się funkcjonalną stroną rzeczy. co do kapitalizacji klasy i właściwości, po prostu zapomniałem, kiedy pisałem powyższy przykład.
gdp

1
Dlaczego O (n ^ 2)? Czy nie jest to O (n * m), ponieważ mówimy o dwóch zmiennych, a nie jednej? Ponieważ m (parametry) są stałą, to jest to samo co O (n). Nie widzę, jak przecięcie powinno być tutaj znacznie szybsze? Ale uzgodniono, że Intersect może być szybszy, ale nie jest gwarantowany.
Squazz

Masz rację, że powinno być O (n * m) - m nie jest jednak stałą - jest to wielkość jednej z list, mimo że w podanym przykładzie może to być „2”. W praktyce nawet wartości stałe nie są pomijalne - dla wszystkich nietrywialnych długości list Intersectbędzie szybszy - jeśli listy są trywialnie krótkie, nie ma to znaczenia (w takim przypadku wydajność prawdopodobnie i tak nie jest dla Ciebie ważna )
BrokenGlass

jak możesz znaleźć indeks listy, w którym warunek staje się prawdziwy? Mam listę ze zdaniami. Mam tablicę z określonymi słowami. Chcę indeksów listy, jeśli zdanie zawiera co najmniej jedno słowo z tablicy. @BrokenGlass
kirushan

1
Pod względem wydajności nie parameters.Any(x => myStrings.Contains(x.source));byłby lepszy niż twój pierwszy przykład?
Fluppe

5

Oto przykład, aby sprawdzić, czy na innej liście znajdują się pasujące elementy

List<int> nums1 = new List<int> { 2, 4, 6, 8, 10 };
List<int> nums2 = new List<int> { 1, 3, 6, 9, 12};

if (nums1.Any(x => nums2.Any(y => y == x)))
{
    Console.WriteLine("There are equal elements");
}
else
{
    Console.WriteLine("No Match Found!");
}

2
Zauważ, że jeśli listy, których to dotyczy, są duże, skończy się to o wiele wolniej niż Intersectpodejście, ponieważ jest to O (N * M) w rozmiarach list. (W pamięci jest O (1).)
Jon Skeet,

1

Jeśli obie listy są zbyt duże i użyjemy wyrażenia lamda, pobranie zajmie dużo czasu. W tym przypadku lepiej użyć linq do pobrania listy parametrów:

var items = (from x in parameters
                join y in myStrings on x.Source equals y
                select x)
            .ToList();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.