2009-10-14 13 views
121

Ho un List<BuildingStatus> chiamato buildingStatus. Vorrei verificare se contiene uno stato il cui codice char (restituito da GetCharCode()) è uguale a qualche variabile, v.Status.LINQ: "contiene" e una query Lambda

C'è un modo per farlo, lungo le linee del codice (non compilato) sotto?

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

risposta

232

Uso Any() invece di Contains():

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

Bello. Continuo a chiedermi perché in Terra Linq non fornisca un metodo 'Contains()', e poi mi rendo conto che si suppone che sia "Qualsiasi()" invece. +1 – Nolonar

30

Il metodo LINQ estensione Qualsiasi potrebbe funzionare per voi ...

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

Non sono sicuro esattamente quello che' sto 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 i risultati attesi:

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

Questo programma confronta una rappresentazione di stringa enum e produce lo stesso risultato:

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 estensione convertire uno IEnumerable in un altro, ma non sono sicuro di quanto sia efficiente; potrebbe semplicemente creare una lista 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 dove:

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

e saltare la creazione del List<string> con ConvertAll() all'inizio.

+0

Grazie larry che ha funzionato, ecco cosa ho fatto facendo riferimento al tuo codice ... Ma sarebbe bello se possibile se non dovessi creare una nuova lista ???? // Utilizzato perché è un ILIST ed esegue il mio GetCharValue // questo produce un elenco "NUOVO" con il mio char's var statusStringList = building.ToList(). ConvertAll (st => st.GetCharValue()); var test = da v in qry dove statusStringList.Contains (v.Status) selezionare v; Tutte le opere, come dico io sarebbe bello non dover fare una nuova lista o usare un lambda dentro Contiene ma sembra NON possibile? –

+0

Presumo che la proprietà status sia una stringa; devi quindi convertire l'enumerazione di stato in stringhe per ogni confronto. Potresti anche convertirli una volta all'inizio e averne fatto. – XXXXX

+0

Ho apportato una modifica che semplifica in modo significativo la domanda ma, in tal modo, sminuisce la risposta. Mi dispiace, ma ho pensato che fosse per il bene generale. –

-1

Se ho capito bene, è necessario convertire il tipo (valore char) che si memorizza nella lista Costruire al tipo (enum) che si memorizza nella lista buildingStatus.

(Per ogni stato nella costruzione della lista // // valore di carattere, fa esiste lo stato nella lista 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; 
} 
+0

-1; mentre la mia modifica alla domanda ha leggermente invalidato questa risposta rimuovendo tutto il riferimento a 'Building' dalla domanda, questo era già * veramente rotto *. 'foreach (valore Enum in Enum.GetValues ​​(typeof (buildingStatus)))' non ha senso. –

0

Ecco come è possibile utilizzare per Contains raggiungere ciò che si desidera:

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