LINQ: «содержит» и лямбда-запрос


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

Эта программа сравнивает строковое представление перечисления и выдает тот же результат:

    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 на:

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

и пропустите создание List<string>с ConvertAll ()в начале.


Спасибо Ларри, который работал, вот что я сделал, сославшись на ваш код ... Но было бы неплохо, если возможно, если бы мне не нужно было создавать новый список ???? // Используем ToList, потому что это ILIST и запускаем мой GetCharValue // это создает «НОВЫЙ» список с моей переменной var statusStringList = building.ToList (). ConvertAll <char> (st => st.GetCharValue ()); var test = из v в qry, где statusStringList.Contains (v.Status) select v; Все работает, как я уже сказал, было бы неплохо не создавать новый список или использовать лямбду внутри Contains, но кажется, что это НЕ ВОЗМОЖНО?
Марк Смит

Я предполагаю, что свойство status является строкой; поэтому вы должны конвертировать перечисления статуса в строки для каждого сравнения. Вы могли бы также преобразовать их один раз в начале и покончить с этим.
XXXXX

Я сделал правку, которая значительно упрощает вопрос, но при этом как бы отменяет действие этого ответа. Извините за это, но я решил, что это было для общего блага.
Марк Эмери

-1

Если я правильно понимаю, вам нужно преобразовать тип (значение char), который вы храните в списке Building, в тип (enum), который вы храните в списке buildingStatus.

(Для каждого статуса в списке Building // символьное значение // существует ли статус в списке buildingStatus // enum value //)

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.