Проверка, пуст ли список с LINQ

Swift 4

func index(of element: Element) -> Int?

var alphabets = ["A", "B", "E", "D"]

Пример1

let index = alphabets.index(where: {$0 == "A"})

Пример2

if let i = alphabets.index(of: "E") {
    alphabets[i] = "C" // i is the index
}
print(alphabets)
// Prints "["A", "B", "C", "D"]"
122
задан Chi 31 October 2012 в 15:02
поделиться

10 ответов

Вы могли сделать это:

public static Boolean IsEmpty<T>(this IEnumerable<T> source)
{
    if (source == null)
        return true; // or throw an exception
    return !source.Any();
}

Редактирование : Обратите внимание, что просто использование.Count метода будет быстро, если базовый источник на самом деле будет иметь быстрое свойство Count. Допустимая оптимизация выше должна была бы обнаружить несколько базовых типов и просто использовать.Count свойство тех, вместо.Any () подход, но затем отступить к.Any (), если никакая гарантия не может быть сделана.

100
ответ дан 24 November 2019 в 01:26
поделиться

@Konrad, что удивляет меня, - то, что в моих тестах, я передаю список в метод, который принимает IEnumerable<T>, таким образом, время выполнения не может оптимизировать его путем называния количества () дополнительным методом для IList<T>.

я могу только предположить, что количество () дополнительный метод для IEnumerable делает что-то вроде этого:

public static int Count<T>(this IEnumerable<T> list)
{
    if (list is IList<T>) return ((IList<T>)list).Count;

    int i = 0;
    foreach (var t in list) i++;
    return i;
}

..., другими словами, немного оптимизации во время выполнения для особого случая IList<T>.

РЕДАКТИРОВАНИЕ / @Konrad +1 помощник - Вы правы относительно этого более вероятно находиться на ICollection<T>.

3
ответ дан 24 November 2019 в 01:26
поделиться

Вторая опция намного более быстра, если у Вас есть несколько объектов.

  • Any() возвраты, как только 1 объект найден.
  • Count() должен продолжать проходить весь список.

, Например, предполагают, что перечисление имело 1 000 объектов.

  • Any() проверил бы первый, затем возвратил бы true.
  • Count() возвратился бы 1000 после пересечения всего перечисления.

Это потенциально хуже при использовании одного из переопределений предиката - количество () все еще должно проверить каждый объект, даже это там - только одно соответствие.

Вы привыкаете к использованию Любого - это действительно имеет смысл и читаемо.

Один протест - если у Вас есть Список, а не просто IEnumerable затем использует свойство Count того списка.

3
ответ дан 24 November 2019 в 01:26
поделиться

Я просто описал быстрый тест, попробуйте это:

 IEnumerable<Object> myList = new List<Object>();

 Stopwatch watch = new Stopwatch();

 int x;

 watch.Start();
 for (var i = 0; i <= 1000000; i++)
 {
    if (myList.Count() == 0) x = i; 
 }
 watch.Stop();

 Stopwatch watch2 = new Stopwatch();

 watch2.Start();
 for (var i = 0; i <= 1000000; i++)
 {
     if (!myList.Any()) x = i;
 }
 watch2.Stop();

 Console.WriteLine("myList.Count() = " + watch.ElapsedMilliseconds.ToString());
 Console.WriteLine("myList.Any() = " + watch2.ElapsedMilliseconds.ToString());
 Console.ReadLine();

второе почти в три раза медленнее :)

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

, Таким образом, я предполагаю, что это зависит от типа списка, который Вы используете!

(Только для указания я поместил 2000 +, объекты в Списке и количестве были еще быстрее, напротив с другими типами)

6
ответ дан 24 November 2019 в 01:26
поделиться

сам LINQ должен делать некоторую серьезную оптимизацию вокруг количества () метод так или иначе.

это удивляет Вас? Я предполагаю, что для IList реализации, Count просто чтения число элементов непосредственно, в то время как Any должен запросить IEnumerable.GetEnumerator метод, создают экземпляр и вызов MoveNext, по крайней мере, однажды.

РЕДАКТИРОВАНИЕ / @Matt:

я могу только предположить, что количество () дополнительный метод для IEnumerable делает что-то вроде этого:

Да, конечно, это делает. Это - то, что я имел в виду. На самом деле это использует ICollection вместо IList, но результатом является то же.

8
ответ дан 24 November 2019 в 01:26
поделиться

Этот метод расширения работает для меня:

public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
    try
    {
        enumerable.First();
        return false;
    }
    catch (InvalidOperationException)
    {
        return true;
    }
}
-5
ответ дан 24 November 2019 в 01:26
поделиться

Хорошо, а что насчет этого?

public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
    return !enumerable.GetEnumerator().MoveNext();
}

РЕДАКТИРОВАТЬ: Я только что понял, что кто-то уже набросал это решение. Было упомянуто, что это сделает метод Any (), но почему бы не сделать это самому? С уважением

1
ответ дан 24 November 2019 в 01:26
поделиться

Другая идея:

if(enumerable.FirstOrDefault() != null)

Однако мне больше нравится подход Any ().

1
ответ дан 24 November 2019 в 01:26
поделиться

List.Count равен O (1) согласно документации Microsoft:
http://msdn.microsoft.com/en-us/library/27b47ht3.aspx

, поэтому просто используйте List.Count == 0 это намного быстрее, чем запрос

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

4
ответ дан 24 November 2019 в 01:26
поделиться

Я бы сделал одно небольшое дополнение к коду, на котором вы, кажется, остановились: проверьте также ICollection, так как это реализовано даже некоторыми неустаревшими универсальными классами, такими как хорошо (т. е. Queue и Stack). Я бы также использовал as вместо is, так как это более идиоматично и , как было показано, быстрее.

public static bool IsEmpty<T>(this IEnumerable<T> list)
{
    if (list == null)
    {
        throw new ArgumentNullException("list");
    }

    var genericCollection = list as ICollection<T>;
    if (genericCollection != null)
    {
        return genericCollection.Count == 0;
    }

    var nonGenericCollection = list as ICollection;
    if (nonGenericCollection != null)
    {
        return nonGenericCollection.Count == 0;
    }

    return !list.Any();
}
14
ответ дан 24 November 2019 в 01:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: