LINQ: "contiene" e una query Lambda


168

Ho List<BuildingStatus>chiamato buildingStatus. Mi piacerebbe verifica se contiene uno stato la cui char codice (restituito da GetCharCode()) è uguale a qualche variabile, v.Status.

C'è un modo per farlo, seguendo le linee del codice (non di compilazione) qui sotto?

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

Risposte:


320

Usa Any()invece di Contains():

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

13
Bello. Continuo a chiedermi perché sulla Terra Linq non fornisca un Contains()metodo, e poi mi rendo conto che dovrebbe essere Any()invece. +1
Nolonar,

38

Il metodo di estensione Linq Any potrebbe funzionare per te ...

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

4

Ecco come è possibile utilizzare Containsper ottenere ciò che si desidera:

buildingStatus.Select(item => item.GetCharValue()).Contains(v.Status) questo restituirà un valore booleano.


3

Non sono sicuro esattamente cosa stai cercando, ma questo programma:

    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);
    }

produce l'output previsto:

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

Questo programma confronta una rappresentazione in forma di stringa dell'enum e produce lo stesso output:

    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 ();
    }

Ho creato questo metodo di estensione per convertire un IEnumerable in un altro, ma non sono sicuro di quanto sia efficiente; potrebbe semplicemente creare un elenco dietro le quinte.

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

Quindi è possibile modificare la clausola where in:

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

e salta creando il List<string>con ConvertAll ()all'inizio.


Grazie Larry che ha funzionato, ecco cosa ho fatto facendo riferimento al tuo codice ... Ma sarebbe bello se possibile se non avessi dovuto creare un nuovo elenco ???? // ToList usato perché è un ILIST ed esegue il mio GetCharValue // questo produce un elenco "NUOVO" con var statusStringList = building.ToList (). ConvertAll <char> (st => st.GetCharValue ()); var test = from v in qry dove statusStringList.Contains (v.Status) seleziona v; Tutto funziona, come ho detto, sarebbe bello non dover fare una nuova lista o usare un lambda all'interno di Contiene ma sembra che NON sia possibile?
Mark Smith

Presumo che la proprietà status sia una stringa; è quindi necessario convertire gli enum di stato in stringhe per ogni confronto. Potresti anche convertirli una volta all'inizio e aver finito.
XXXXX,

Ho apportato una modifica che semplifica in modo significativo la domanda ma, nel farlo, annulla in qualche modo questa risposta. Mi dispiace, ma ho pensato che fosse per il bene più grande nel complesso.
Mark Amery,

-1

Se ho capito bene, è necessario convertire il tipo (valore char) che si memorizza nell'elenco degli edifici nel tipo (enum) che si memorizza nell'elenco degli edifici.

(Per ogni stato nell'elenco Building // valore carattere //, esiste lo stato nell'elenco buildingStatus // valore enum //)

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; mentre la mia modifica alla domanda ha leggermente invalidato questa risposta rimuovendo tutti i riferimenti a Buildingdalla domanda, questo è già stato effettivamente interrotto . foreach(Enum value in Enum.GetValues(typeof(buildingStatus)))è una sciocchezza.
Mark Amery,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.