LINQ: "містить" і запит Lambda


168

У мене є List<BuildingStatus>дзвінок buildingStatus. Я хотів би, щоб перевірити , чи містить він статус , чий символ коди (повертається GetCharCode()) дорівнює деякі змінні v.Status.

Чи є якийсь спосіб зробити це, відповідно до наведеного нижче коду (некомпілюючий) код?

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

Відповіді:


320

Використовуйте Any()замість Contains():

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

13
Приємно. Мені постійно цікаво, чому на Землі Linq не пропонує Contains()метод, і тоді я розумію, що це має бути Any()замість цього. +1
Нолонар

38

Метод розширення Linq Будь-який може працювати для вас ...

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

4

Ось як можна використати Containsдля досягнення того, що ви хочете:

buildingStatus.Select(item => item.GetCharValue()).Contains(v.Status) це поверне булеве значення.


3

Я не впевнений, що саме ви шукаєте, але ця програма:

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

дає очікуваний вихід:

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

Ця програма порівнює рядкове представлення enum і дає такий же вихід:

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

Я створив цей метод розширення для перетворення одного IEnumerable в інший, але я не впевнений, наскільки він ефективний; він може просто створити список поза кадром.

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

Тоді ви можете змінити пункт де на:

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

і пропустити створюючи List<string>з ConvertAll ()самого початку.


Дякую Ларрі, який працював, ось що я зробив, переглянувши свій код ... Але було б добре, якщо можливо, якби мені не довелося створювати новий список ???? // Використовується ToList, тому що це ILIST та запускає мій GetCharValue // це створює список "НОВОГО" зі статусом var мого charStringList = building.ToList (). ConvertAll <char> (st => st.GetCharValue ()); var test = від v in qry, де statusStringList.Contains (v.Status) вибираємо v; Все працює, як я вважаю, було б непогано не робити новий список або використовувати лямбда всередині Містить, але видається, що НЕ можливо?
Марк Сміт

Я припускаю, що властивість статусу є рядком; тому для кожного порівняння вам доведеться конвертувати перерахунки стану в рядки. Ви можете також перетворити їх один раз на початку і зробити це з ним.
XXXXX

Я вніс редакцію, яка значно спрощує питання, але, роблячи це, начебто визнає недійсним цю відповідь. Вибачте з цього приводу, але я подумав, що це на користь загалом.
Марк Амерді

-1

Якщо я правильно розумію, вам потрібно перетворити тип (char значення), який ви зберігаєте у списку Building, у тип (enum), який ви зберігаєте у списку buildingStatus.

(Для кожного статусу в списку будівель // значення символу // чи існує статус у списку buildingStatus // значення 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; в той час, як моя редакція запитання трохи визнала недійсною цю відповідь, видаливши всі посилання на Buildingзапитання, це було дійсно порушено . foreach(Enum value in Enum.GetValues(typeof(buildingStatus)))- це нісенітниця.
Марк Амері
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.