LINQ: „zawiera” i zapytanie lambda


168

Mam List<BuildingStatus>telefon buildingStatus. Chciałbym sprawdzić, czy zawiera on status której char code (zwrócony przez GetCharCode()) równa jakąś zmienną v.Status.

Czy jest jakiś sposób na zrobienie tego, zgodnie z liniami poniższego (niekompilującego) kodu?

buildingStatus.Contains(item => item.GetCharValue() == v.Status)

Odpowiedzi:


320

Użyj Any()zamiast Contains():

buildingStatus.Any(item => item.GetCharValue() == v.Status)

13
Miły. Ciągle się zastanawiam, dlaczego u licha Linq nie oferuje Contains()metody, a potem zdaję sobie sprawę, że tak powinno być Any(). +1
Nolonar

38

Metoda rozszerzenia Linq Any może działać dla Ciebie ...

buildingStatus.Any(item => item.GetCharValue() == v.Status)

4

Oto, jak możesz Containsosiągnąć to, czego chcesz:

buildingStatus.Select(item => item.GetCharValue()).Contains(v.Status) zwróci to wartość logiczną.


3

Nie jestem pewien, czego dokładnie szukasz, ale ten program:

    public class Building
    {
        public enum StatusType
        {
            open,
            closed,
            weird,
        };

        public string Name { get; set; }
        public StatusType Status { get; set; }
    }

    public static List <Building> buildingList = new List<Building> ()
    {
        new Building () { Name = "one", Status = Building.StatusType.open },
        new Building () { Name = "two", Status = Building.StatusType.closed },
        new Building () { Name = "three", Status = Building.StatusType.weird },

        new Building () { Name = "four", Status = Building.StatusType.open },
        new Building () { Name = "five", Status = Building.StatusType.closed },
        new Building () { Name = "six", Status = Building.StatusType.weird },
    };

    static void Main (string [] args)
    {
        var statusList = new List<Building.StatusType> () { Building.StatusType.open, Building.StatusType.closed };

        var q = from building in buildingList
                where statusList.Contains (building.Status)
                select building;

        foreach ( var b in q )
            Console.WriteLine ("{0}: {1}", b.Name, b.Status);
    }

daje oczekiwany wynik:

one: open
two: closed
four: open
five: closed

Ten program porównuje ciąg reprezentujący wyliczenie i generuje te same dane wyjściowe:

    public class Building
    {
        public enum StatusType
        {
            open,
            closed,
            weird,
        };

        public string Name { get; set; }
        public string Status { get; set; }
    }

    public static List <Building> buildingList = new List<Building> ()
    {
        new Building () { Name = "one", Status = "open" },
        new Building () { Name = "two", Status = "closed" },
        new Building () { Name = "three", Status = "weird" },

        new Building () { Name = "four", Status = "open" },
        new Building () { Name = "five", Status = "closed" },
        new Building () { Name = "six", Status = "weird" },
    };

    static void Main (string [] args)
    {
        var statusList = new List<Building.StatusType> () { Building.StatusType.open, Building.StatusType.closed };
        var statusStringList = statusList.ConvertAll <string> (st => st.ToString ());

        var q = from building in buildingList
                where statusStringList.Contains (building.Status)
                select building;

        foreach ( var b in q )
            Console.WriteLine ("{0}: {1}", b.Name, b.Status);

        Console.ReadKey ();
    }

Utworzyłem tę metodę rozszerzenia, aby przekonwertować jeden IEnumerable na inny, ale nie jestem pewien, jak wydajna jest; może po prostu utworzyć listę zakulisową.

public static IEnumerable <TResult> ConvertEach (IEnumerable <TSource> sources, Func <TSource,TResult> convert)
{
    foreach ( TSource source in sources )
        yield return convert (source);
}

Następnie możesz zmienić klauzulę where na:

where statusList.ConvertEach <string> (status => status.GetCharValue()).
    Contains (v.Status)

i pomiń tworzenie List<string>z ConvertAll ()na początku.


Dzięki Larry, że zadziałało, oto co zrobiłem, odnosząc się do twojego kodu ... Ale byłoby miło, gdyby to było możliwe, gdybym nie musiał tworzyć nowej listy ???? // Użyto ToList, ponieważ jest to ILIST i uruchom moją GetCharValue // w ten sposób zostanie utworzona lista „NOWA” z var statusStringList = building.ToList (). ConvertAll <char> (st => st.GetCharValue ()); var test = from v w qry gdzie statusStringList.Contains (v.Status) select v; Wszystko działa, jak mówię, byłoby miło nie robić nowej listy lub używać lambdy wewnątrz Contains, ale wydaje się, że NIE jest to możliwe?
mark smith

Zakładam, że właściwość status jest ciągiem znaków; dlatego dla każdego porównania należy przekonwertować wyliczenia stanu na ciągi. Równie dobrze możesz przekonwertować je raz na początku i skończyć z tym.
XXXXX

Dokonałem edycji, która znacznie upraszcza pytanie, ale czyniąc to, w pewnym sensie unieważnia tę odpowiedź. Przepraszam za to, ale pomyślałem, że ogólnie było to dla dobra.
Mark Amery,

-1

Jeśli dobrze rozumiem, musisz przekonwertować typ (wartość znaku), który przechowujesz na liście budynków, na typ (wyliczenie), który przechowujesz na liście buildingStatus.

(Dla każdego statusu na liście budynków // wartość znakowa //, czy status istnieje na liście buildingStatus // wartość wyliczenia //)

public static IQueryable<Building> WithStatus(this IQueryable<Building> qry,  
IList<BuildingStatuses> buildingStatus) 
{ 
    return from v in qry
           where ContainsStatus(v.Status)
           select v;
} 


private bool ContainsStatus(v.Status)
{
    foreach(Enum value in Enum.GetValues(typeof(buildingStatus)))
    {
        If v.Status == value.GetCharValue();
            return true;
    }

    return false;
}

-1; podczas gdy moja edycja pytania nieznacznie unieważniła tę odpowiedź, usuwając Buildingz pytania wszystkie odniesienia do , to zostało już naprawdę zepsute . foreach(Enum value in Enum.GetValues(typeof(buildingStatus)))to nonsens.
Mark Amery,
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.