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.