Расширение LINQ MoreThan(predicate, limit) вместо Count(predicate) › limit?

Каков наилучший способ проверить, содержит ли коллекция IEnumerable больше или меньше X элементов, соответствующих предикату?

В настоящее время я использую .Count(lambda) <= limit, но это заставляет программу излишне перебирать всю коллекцию.


person Erwin Mayer    schedule 26.07.2011    source источник


Ответы (2)


Вы можете определить некоторые методы расширения:

static bool LessThan<T>(this IEnumerable<T> enumerable, int count, Func<T, bool> predicate)
{
    int found = 0;
    foreach (var item in enumerable)
    {
        if (predicate(item))
        {
            found++;
            if (found >= count)
                return false;
        }
    }
    return true;
}

static bool MoreThan<T>(this IEnumerable<T> enumerable, int count, Func<T, bool> predicate)
{
    int found = 0;
    foreach (var item in enumerable)
    {
        if (predicate(item))
        {
            found++;
            if (found > count)
                return true;
        }
    }
    return false;
}

а затем используйте их так:

var col = new[] { 1, 6, 4, 8, 3, 5, 1, 7 };
var res1 = col.MoreThan(2, c => c == 1); //false
var res2 = col.MoreThan(1, c => c == 1); //true
var res3 = col.LessThan(4, c => c > 5); //true
var res4 = col.LessThan(3, c => c > 5); //false
person Kylar    schedule 26.07.2011
comment
Очень хорошо, хотя, наверное, должно быть (Найдено › количество) в первом и (Найдено ›= количество) во втором. - person Erwin Mayer; 26.07.2011
comment
Это заставило бы их возвращать true, когда количество совпадающих элементов равно количеству, которое вы ищете, что не имеет смысла для имен LessThan и MoreThan. - person Kylar; 27.07.2011

Вы можете использовать это выражение: .Skip(limit).Any() эквивалентно Count() > limit. Но если ваш список ICollection, то Count() предпочтительнее.

Версия предиката:

public static bool MoreThan<TSource>(this IEnumerable<TSource> source, 
    Func<TSource, bool> predicate, int limit)
{
    int i = 0;

    foreach (var item in source)
    {
        if (predicate(item))
        {
            i++;

            if (i > limit)
            {
                return true;
            }
        }

    }

    return false;
}
person Kirill Polishchuk    schedule 26.07.2011
comment
Как это отвечает на вопрос? Элементы, соответствующие предикату, как задается вопрос, не учитываются. - person Kylar; 26.07.2011
comment
@Kirill, SkipWhile (предикат) вернет все элементы, как только условие больше не будет выполняться. - person Erwin Mayer; 26.07.2011
comment
@ Эрвин, правда. Я удаляю это из своего ответа. - person Kirill Polishchuk; 26.07.2011
comment
@Erwin, если вы используете .Count(predicate), я думаю, что это наиболее подходящее решение. - person Kirill Polishchuk; 26.07.2011