Операции Count, LongCount и Sum

26

Count

Операция Count возвращает количество элементов во входной последовательности. Эта операция имеет два прототипа, описанные ниже:

Первый прототип Count
public static int Count<T>( 
      this IEnumerable<T> source);

Этот прототип операции Count возвращает общее количество элементов во входной последовательности, проверяя сначала, реализует ли она интерфейс ICollection<T>, и если да, то получает счетчик последовательности через реализацию этого интерфейса. Если же входная последовательность source не реализует интерфейс ICollection<T>, операция Count перечисляет всю эту последовательность, подсчитывая количество элементов.

Второй прототип Count

Второй прототип операции Count перечисляет входную последовательность source и подсчитывает все элементы, которые заставляют делегат метода predicate вернуть true:

public static int Count<T>( 
      this IEnumerable<T> source, 
      Func<T, bool> predicate);

Если любой из аргументов равен null, генерируется исключение ArgumentNullException. Если значение count превышает Int32.MaxValue, генерируется исключение OverflowException.

Код ниже начинается с использования первого прототипа. Сколько элементов содержится в последовательности cars? Затем используется второй прототип, подсчитывая количество машин, начинающихся с "A":

string[] cars = { "Alfa Romeo", "Aston Martin", "Audi", "Nissan", "Chevrolet",  "Chrysler", "Dodge", "BMW", 
                            "Ferrari",  "Bentley", "Ford", "Lexus", "Mercedes", "Toyota", "Volvo", "Subaru", "Жигули :)"};

Console.WriteLine("Операция Count\n\n********\n");

int count = cars.Count();
Console.WriteLine("Количество элементов в массиве Cars: " + count);

count = cars.Count(s => s.StartsWith("A"));
Console.WriteLine("Количество элементов в массиве Cars начинающихся с \"A\": " + count);

Результат работы этого кода:

Использование операции Count

LongCount

Операция LongCount возвращает количество элементов входной последовательности как значение типа long. Эта операция имеет два прототипа, полностью идентичных прототипам операции Count, за тем лишь исключением, что они возвращают число элементов, имеющих тип long, а не int.

Давайте рассмотрим пример использования операции LongCount. Можно было бы просто повторить тот же пример, который сопровождал описание операции Count, изменив соответствующие места на тип long, но это не слишком наглядно. Поскольку нереально описать достаточно длинную статическую последовательность, для которой понадобилась бы операция LongCount, она генерируется с помощью стандартной операции запроса:

long count = Enumerable.Range(0, int.MaxValue)
                .Concat(Enumerable.Range(0, int.MaxValue)).LongCount();
Console.WriteLine("Количество элементов в count: " + count);

// Используем второй прототип
count = Enumerable.Range(0, int.MaxValue)
       .Concat(Enumerable.Range(0, int.MaxValue))
       .LongCount(s => s % 2 == 0);
Console.WriteLine("Количество четных элементов в count: " + count);

Как видите, были сгенерированы две последовательности с использованием операции Range и соединены вместе с помощью операции Concat.

Перед запуском примера наберитесь терпения — он выполняется долго, возможно, даже несколько минут. Например, на машине с четырехядерным процессором и 4 Гбайт памяти для этого потребовалось около минуты. В конце концов, будут сгенерированы две последовательности, каждая по 2 147 483 647 элементов. Ниже показан результат:

Использование операции LongCount

Sum

Операция Sum возвращает сумму числовых значений, содержащихся в элементах последовательности. Эта операция имеет два прототипа, описанные ниже:

Первый прототип Sum
public static Numeric Sum( 
   this IEnumerable<Numeric> source);

Тип Numeric должен быть одним из int, long, double или decimal, либо одним из их допускающих null эквивалентов: int?, long?, double? или decimal?.

Первый прототип операции Sum возвращает сумму всех элементов входной последовательности source. Пустая последовательность приведет к возврату нуля. Операция Sum не включает значения null в результат для числовых типов, допускающих null.

Второй прототип Sum

Второй прототип Sum ведет себя так же, как и первый, но суммирует только те значения входной последовательности, которые выбраны делегатом метода selector.

public static Numeric Sum<T>( 
        this IEnumerable<T> source, 
        Func<T, Numeric> selector);

Если любой из аргументов равен null, генерируется исключение ArgumentNullException. Если сумма оказывается слишком большой, чтобы уместиться в тип Numeric, и если тип Numeric отличается от decimal или decimal?, генерируется исключение OverflowException. Если же типом Numeric является decimal или decimal?, возвращается положительная или отрицательная бесконечность.

Ниже показан пример использования первого прототипа операции Sum:

IEnumerable<int> ints = Enumerable.Range(1, 100);

int sum = ints.Sum();
Console.WriteLine("Сумма чисел от 1 до 100: " + sum);
Вызов первого прототипа операции Sum

Теперь попробуем второй прототип, как показано ниже. В этом примере задействован общий класс EmployeeOptionEntry, и будут суммироваться опционы для всех сотрудников:

IEnumerable<EmployeeOptionEntry> options =
        EmployeeOptionEntry.GetEmployeeOptionEntries();

long optionsSum = options.Sum(o => o.optionsCount);
Console.WriteLine("Сумма опционов сотрудников: {0}", optionsSum);

Вместо того чтобы пытаться суммировать весь элемент, что не имело бы смысла в данном примере, поскольку речь идет об объекте сотрудника, можно использовать элемент selector второго прототипа, чтобы извлечь только интересующие члены — в данном случае optionsCount. Результат выполнения этого кода показан ниже:

Вызов второго прототипа операции Sum
Пройди тесты
Лучший чат для C# программистов