Простая проверка, чтобы увидеть, имеет ли хотя бы один объект в наборе значение свойства TRUE - PullRequest
7 голосов
/ 19 сентября 2010

У меня есть набор объектов модели с открытым логическим свойством IsVisible. Все, что мне нужно сделать, это найти, если хотя бы один из наборов имеет значение, установленное на TRUE. Другими словами, если у меня есть 10000 объектов, но второй - true, мне не нужно прокручивать остальные 9,998. У меня уже есть мой ответ.

Теперь я знаю, что мог бы написать свою собственную итеративную функцию и перейти к первому значению 'True', но я надеюсь, что это может сделать LINQ. На самом деле, это даже не должно быть LINQ. Любые предложения приветствуются.

Кстати, язык выбора - C #.

Обновление:

Смотрите мой последний пост здесь. Я добавил тестовый код и тайминги. Кажется, что LINQ чертовски плох с точки зрения производительности по сравнению с тем, чтобы самому сделать тест. Конечно, писать легче, но в критически важные моменты я больше не уверен.

Что меня удивило, так это то, что большую часть времени я выполнял их, перечисление выиграло и добросовестно, но по какой-то причине, когда я завернул тест за несколько проходов, похоже, он переключился на индексирование с кэшированным считается самым быстрым.

Я также заметил, что если я не верну все обратно на «ложь», все оставшиеся / повторные тесты будут казаться НАМНОГО быстрее. Каким-то образом переустановка всего на ЛОЖЬ (что было намеренно излишним, чтобы проверить именно это ...) меняет дело.

Интересно. Не уверен, куда я пойду сейчас. Эта не является критически важной системой, поэтому, возможно, я пойду на удобство чтения, но все же. Интересно.

Ответы [ 3 ]

17 голосов
/ 19 сентября 2010

Метод, который вы ищете: Enumerable.Any.

bool anyObjectsVisible = myObjects.Any(myObject => myObject.IsVisible);

Это имеет точную семантику короткого замыкания, которую вы ищете;пример кода похож на:

static bool AreAnyObjectsVisible(IEnumerable<MyObject> myObjects)
{
    foreach (var myObject in myObjects)
    {
        if (myObject.IsVisible) return true;
    }

    return false;
}
3 голосов
/ 19 сентября 2010

Если вам действительно нужно найти объект, просто используйте метод .First или .FirstOrDefault:

var myObject = myCollection.First(x=>x.IsVisible);

или

var myObject = myCollection.FirstOrDefault(x=>x.IsVisible);

Единственное различие между ними заключается в том, что метод .First вызовет исключение, если в коллекции нет такого объекта, когда второй возвращает значение по умолчанию (в этом примере - null).

Если вам просто нужно проверить, есть ли какой-либо объект с этим набором свойств, используйте

var thereIsVisibleObject = myCollection.Any(x=>x.IsVisible);

Все эти методы прекращают итерацию по коллекции, когда соответствующий объект найден.

Или, если вы проверите, являются ли все объекты видимыми / невидимыми, вы можете сделать это:

var allTheObjectsAreVisible = myCollection.All(x=>x.IsVisible);
var allTheObjectsAreInvisible = myCollection.All(x=>!x.IsVisible);

Но .Все метод будет перечислять все элементы (что очевидно из его названия).

0 голосов
/ 19 сентября 2010

Вот реализация ".Any ()":

public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (predicate == null)
    {
        throw Error.ArgumentNull("predicate");
    }
    foreach (TSource local in source)
    {
        if (predicate(local))
        {
            return true;
        }
    }
    return false;
}

Так вот, ничего особенного в .Any () нет, это просто обертка вокруг foreach. Ничего особенного, чтобы проверить там, и ничего не винить в плане микро-микро-микро оптимизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...