LINQ: "contém" e uma consulta Lambda

168

Eu tenho um List<BuildingStatus>chamado buildingStatus. Gostaria de verificar se ele contém um status cujo código de char (retornado por GetCharCode()) é igual a alguma variável v.Status,.

Existe alguma maneira de fazer isso, seguindo as linhas do código (não compilável) abaixo?

buildingStatus.Contains(item => item.GetCharValue() == v.Status)
Mark Smith
fonte

Respostas:

320

Use em Any()vez de Contains():

buildingStatus.Any(item => item.GetCharValue() == v.Status)
Rex M
fonte
13
Agradável. Fico me perguntando por que, na Terra, o Linq não fornece um Contains()método, e então percebo que deveria ser Any(). +1
Nolonar
38

O método de extensão Linq Any poderia funcionar para você ...

buildingStatus.Any(item => item.GetCharValue() == v.Status)
flq
fonte
4

Aqui está como você pode usar Containspara alcançar o que deseja:

buildingStatus.Select(item => item.GetCharValue()).Contains(v.Status) isso retornará um valor booleano.

Soft-Brain
fonte
3

Não sei exatamente o que você está procurando, mas este programa:

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

produz a saída esperada:

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

Este programa compara uma representação de string do enum e produz a mesma saída:

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

Criei esse método de extensão para converter um IEnumerable em outro, mas não tenho certeza de quão eficiente é; pode apenas criar uma lista nos bastidores.

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

Em seguida, você pode alterar a cláusula where para:

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

e pule a criação de List<string>com ConvertAll ()no início.

XXXXX
fonte
Obrigado Larry que trabalhou, aqui está o que eu fiz referindo-se ao seu código ... Mas seria bom se possível se eu não tivesse que criar uma nova lista ???? // ToList usado porque é um ILIST e executa meu GetCharValue // isso produz uma lista "NEW" com o var statusStringList do meu char = building.ToList (). ConvertAll <char> (st => st.GetCharValue ()); var test = from v em qry onde statusStringList.Contains (v.Status) seleciona v; Todos os trabalhos, como eu disse, seria bom não ter que fazer uma nova lista ou usar um lambda dentro de Contém, mas parece que NÃO é possível?
Mark Smith
Presumo que a propriedade status seja uma string; portanto, você deve converter as enumerações de status em seqüências de caracteres para cada comparação. Você também pode convertê-los uma vez no início e pronto.
XXXXX
Fiz uma edição que simplifica significativamente a pergunta, mas, ao fazer isso, invalida essa resposta. Desculpe por isso, mas achei que era para o bem maior em geral.
Mark Amery
-1

Se bem entendi, você precisa converter o tipo (valor de char) que você armazena na lista Building para o tipo (enum) que você armazena na lista buildingStatus.

(Para cada status na lista Building // valor do caractere //, o status existe na lista buildingStatus // valor da 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;
}
psabela
fonte
-1; embora minha edição da pergunta tenha invalidado levemente essa resposta, removendo todas as referências Buildingda pergunta, isso já estava realmente quebrado . foreach(Enum value in Enum.GetValues(typeof(buildingStatus)))é um absurdo.
Mark Amery