Как подсчитать количество элементов в списке в R (с примером)
Вы можете использовать следующие методы для подсчета количества элементов в списке в R:
Метод 1: подсчитать количество элементов в списке
length(my_list)
Метод 2: подсчитать количество элементов в определенном компоненте списка
length(my_list[[3]])
Метод 3: подсчитать количество элементов в каждом компоненте списка
lengths(my_list)
В следующих примерах показано, как использовать каждый метод на практике со следующим списком в R:
#define list my_list
Пример 1: подсчет количества элементов в списке
Мы можем использовать функцию length() , чтобы просто подсчитать количество элементов в списке:
#count number of elements in list length(my_list) [1] 3
Мы видим, что в списке 3 элемента.
Пример 2: подсчет количества элементов в определенном компоненте списка
Мы можем использовать функцию length() в сочетании с двойными скобками для подсчета количества элементов в определенном компоненте списка.
Например, мы можем использовать следующий код для подсчета количества элементов в третьем компоненте списка:
#count number of elements in third component of list length(my_list[[3]]) [1] 4
Мы видим, что в третьем компоненте списка есть 4 элемента.
В частности, четыре значения: A, B, C и D.
Пример 3: подсчет количества элементов в каждом компоненте списка
Мы можем использовать функцию lengths() для подсчета количества элементов в каждом отдельном компоненте списка:
#count number of elements in each component of list lengths(my_list) x y z 6 1 4
Из вывода мы видим:
- x имеет 6 элементов (1, 4, 4, 5, 7, 8)
- y имеет 1 элемент («привет»)
- z имеет 4 элемента («A», «B», «C», «D»)
Обратите внимание, что мы также можем использовать функцию sum() с функцией length() для подсчета общего количества отдельных элементов во всем списке:
#count total number of individual elements in entire list sum(lengths(my_list)) [1] 11
Мы видим, что всего в списке 11 элементов.
Дополнительные ресурсы
В следующих руководствах объясняется, как использовать другие распространенные функции в R:
Особенности реализации List в C#
List является одной из самых популярных коллекций в C#. Давайте разберёмся в некоторых особенностях работы с ним и посмотрим на внутреннюю реализацию его отдельных частей.
Введение
Данная статья будет посвящена полностью List из пространства имён System.Collections.Generic, а если быть конкретнее, то его внутренней реализации и некоторым особенностям. Это самая часто используемая коллекция языка. И это не только моё мнение — так писали в своих книгах Эндрю Троелсен, Филипп Джепикс и Джон Скит. И это понятно – с List легко работать. Он довольно гибкий и тем самым покрывает огромную часть повседневных задач программиста. С этим также помогает большое количество методов, идущих с ним в комплекте. А наличие LINQ ещё больше расширяет возможности данной коллекции.
Внутри List
Исходный код класса List доступен на GitHub. Это значит, что мы можем взглянуть на его реализацию. Пройдёмся по важным аспектам.
Класс List представляет последовательный список элементов с динамически изменяемым размером. Под капотом List построен с использованием массива.
Класс List содержит 3 основных поля:
- T[] _items – внутренний массив, на основе которого строится список;
- int _size – хранит информацию о количестве элементов в списке;
- int _version – содержит версию коллекции.
Добавление элемента в список
Как уже было сказано, размер списка динамически изменяется. Взглянем поподробнее, что же происходит при добавлении элемента в список.
public void Add(T item) < _version++; T[] array = _items; int size = _size; if ((uint)size < (uint)array.Length) < _size = size + 1; array[size] = item; >else < AddWithResize(item); >>
В первую очередь значение поля _version увеличивается на 1 (смысл данного действия мы разберём чуть позже). После этого происходит создание двух локальных переменных – массива array с элементами типа T и size типа int. Им присваиваются соответствующие поля. Далее если в массиве ещё есть место для одного элемента, то происходит изменение элемента массива по индексу size + 1. Если же размер массива не позволяет добавить ещё один элемент, то вызывается метод AddWithResize.
private void AddWithResize(T item)
Здесь вызывается метод Grow для увеличения текущего размера внутреннего массива. Далее производятся те же действия, что и в методе Add, для добавления при доступном месте.
Рассмотрим метод Grow подробнее:
private void Grow(int capacity) < . int newcapacity = _items.Length == 0 ? DefaultCapacity : 2 * _items.Length; if ((uint)newcapacity >Array.MaxLength) newcapacity = Array.MaxLength; if (newcapacity
Алгоритм работы метода Grow:
- если внутренний массив пуст, то ёмкость списка будет равна 4, иначе удвоенной длине массива;
- если новое значение ёмкости получается больше максимально возможной длины массива, то данная ёмкость станет равна Array.MaxLength;
- если новое значение ёмкости коллекции получилось меньше текущего, то новая ёмкость станет равна текущей;
- в конце newcapacity записывается в свойство Capacity.
Зачем нужно поле _version?
Но зачем же всё-таки нужно поле _version, значение которого менялось в методе Add? Как уже было написано ранее, это поле, которое позволяет отслеживать версию списка. Его значение проверяется при обходе списка. К примеру, рассмотрим метод ForEach:
public void ForEach(Action action) < . int version = _version; for (int i = 0; i < _size; i++) < if (version != _version) < break; >action(_items[i]); > if (version != _version) ThrowHelper .ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion(); >
Перед началом обхода значение поля _version сохраняется в переменную. Если во время обхода список будет изменён, то обход прекращается и выбрасывается исключение типа System.InvalidOperationException. Похожим образом _version отслеживается и в List.Enumerator. Поэтому изменение списка при его обходе в foreach также приведёт к выбрасыванию исключения.
Capacity
У List есть конструктор, который первым аргументом принимает число – начальную ёмкость.
List list = new List(8);
Если разработчик заранее знает нужный размер списка, то он может задать его. Это избавляет от ненужных операций копирования и выделения памяти под новый массив при добавлении новых элементов.
Кстати, размером внутреннего массива можно управлять, ещё и используя свойство Capacity:
list.Capacity = 8;
Рассмотрим код данного свойства:
public int Capacity < get =>_items.Length; set < if (value < _size) < ThrowHelper.ThrowArgumentOutOfRangeException(. ); >if (value != _items.Length) < if (value >0) < T[] newItems = new T[value]; if (_size >0) < Array.Copy(_items, newItems, _size); >_items = newItems; > else < _items = s_emptyArray; >> > >
Аксессор get возвращает значение _items.Length, то есть длину внутреннего массива.
Аксессор set действует по следующему алгоритму:
- если value меньше количества элементов в коллекции, то будет выброшено исключение;
- если value не равно длине внутреннего массива и value больше 0, то будет создан новый массив с ёмкостью, равной value;
- если количество элементов в списке больше 0, то будет выполнено копирование элементов из старого массива в новый;
- если value равно 0, то полю, которое представляет собой внутренний массив, будет присвоен пустой массив.
Прочие особенности методов List
Insert
Метод Insert позволяет вставить элемент в коллекцию только в рамках начала и конца этой коллекции. Если количество элементов в коллекции будет равно размерности внутреннего массива, то произойдёт увеличение ёмкости массива с помощью метода Grow(_size + 1). При попытке вставить элемент на индекс, который больше list.Count, будет выброшено исключение System.ArgumentOutOfRangeException.
List list = new List() < "1", "2">; list.Insert(1, "10"); // OK list.Insert(2, "15"); // OK list.Insert(10, 12); // throw exception
Подобное поведение останется даже при явном управлении размером внутреннего массива.
List list = new List() < "1", "2">; list.Capacity = 8; list.Insert(3, "3");
В свойство Capacity присваивается 8, что приводит к изменению размера внутреннего массива. Однако это не даёт возможности вставить элемент на позицию, превышающую list.Count. Результатом выполнения приведённого кода будет выбрасывание исключения.
Clear
Данный метод производит очистку коллекции. В результате этой операции свойство Count будет иметь значение 0. Элементы коллекции ссылочного типа получают значение по умолчанию. Если элементы коллекции являются структурами и имеют поля ссылочного типа, то данные поля тоже получат значение по умолчанию. Стоит заметить, что размер внутреннего массива остаётся неизменным. Если до вызова Clear свойство Capacity было равно 8, то и после Clear размер массива останется равным 8. Для освобождения памяти, выделяемой под сам массив, необходимо после Clear вызвать метод TrimExcess.
TrimExcess
Данный метод делает размер внутреннего массива равным количеству элементов в списке. Его стоит использовать, например, когда вы знаете, что в коллекцию больше не будут добавлены новые элементы.
list.Clear(); list.TrimExcess();
Sort и OrderBy
Между двумя этими методами есть несколько различий:
- метод Sort принадлежит классу List , а метод OrderBy является методом расширения из LINQ;
- метод Sort модифицирует исходную коллекцию, а OrderBy возвращает отсортированную копию с типом IOrderedEnumerable ;
- метод OrderBy производит устойчивую сортировку, а Sort – нет. Если вы используете метод Sort, то эквивалентные элементы могут быть переупорядочены.
Немного о производительности
List против ArrayList
List является обобщённым, а это значит, что мы должны при создании списка указать, с объектами какого типа он работает.
List list = new List();
Джеффри Рихтер в своей книге "CLR via C#" приводит следующие преимущества обобщений:
- защита исходного кода;
- безопасность типов;
- более простой и понятный код;
- повышение производительности.
В той же книге в начале 12-ой главы про обобщения имеется хороший пример сравнения List и его необобщённого аналога ArrayList. Суть теста заключается в добавлении элемента в список и присваивании этого же элемента из списка в переменную 10 миллионов раз.
Пример кода для тестирования ArrayList со значимым типом:
public void ValueTypeArrayList() < ArrayList a = new ArrayList(); for (Int32 n = 0; n < _count; n++) < a.Add(n); Int32 x = (Int32)a[n]; >>
Тестирование производилось с объектами значимых (Int32) и ссылочных (String) типов.
Переписав приведённый в книге код и протестировав его с помощью BenchmarkDotNet, я получил следующие результаты:
Из результатов видно, что c Int32 алгоритм List работает гораздо быстрее, чем ArrayList. В целых 13 раз! Плюс с List в 4 раза меньше выделяется память.
Из-за того что при работе ArrayList производится множество операций упаковки, увеличивается и число сборок мусора. При этом получение элемента требует выполнения распаковки. Всё это приводит к снижению производительности.
Разница при использовании ссылочных типов несущественная, так как нет операций упаковки и распаковки, которые являются очень тяжёлыми. Судя по коду, небольшая разница в скорости появляется из-за операции преобразования типов.
Преимущества задания Capacity
Как уже было сказано ранее, если разработчик заранее знает размер списка, то он может указать его.
Проведём небольшой тест.
public void ListWithoutCapacity() < for (int i = 0; i < Count; i++) < Listlist = new List(); for (int j = 0; j < Length; j++) < list.Add(j); >> >
В данном случае происходит добавление в list 150 000 элементов. Для наглядности проведём эту операцию 1000 раз. И сравним производительность с таким же методом, но с указанным capacity, который равен количеству операций добавления.
Из результатов видно, что затраченное время на выполнение метода без capacity в 2 раза больше, чем с заранее установленным. Также памяти выделяется почти в 4 раза больше. Подобные действия убирают 17 ненужных операций копирования на каждой итерации внешнего цикла.
Как быстрее всего определить, что в списке есть элементы?
Возьмём три варианта определения того, что список непустой:
- использовать метод Count из LINQ и сравнить результат с 0;
- использовать свойство Count и сравнить результат с 0;
- использовать метод расширения Any из LINQ.
Проведя тестирование, получаем следующие результаты для списка из 1 500 000 элементов:
Самым быстрым оказался доступ к свойству Count, так как оно просто возвращает значение поля _size.
Метод Count пытается преобразовать исходную коллекцию к ICollection. При успешном преобразовании метод вернёт значение свойства Count. В случае неудачи потребуется обойти всю коллекцию для высчитывания количества элементов. К счастью, List реализует данный интерфейс.
Метод Any при обнаружении хотя бы одного элемента в коллекции вернёт true.
Заключение
Можно сказать, что List является более удобной для работы версией массива. Например, со списком удобнее работать, когда заранее неизвестно количество элементов последовательности.
C# содержит ещё множество коллекций, которые помогают в работе разработчикам. Какие-то из них более специфичные, а какие-то менее. Надеюсь, что данная статья поможет вам в работе и сделает ваше понимание списков чуть лучше :).
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Artem Rovenskii. List in C#: implementation and features.
- Блог компании PVS-Studio
- Программирование
- .NET
- C#
Максимальное количество элементов List
Кто знает, имеет ли объект System.Collections.Generic.List какой то предел количества элементов.
4 ответа
06 июня 2009 года
2 / / 06.06.2009
Запустите добавление элементов в цикле и узнаете, на ккаком индексе упадет программа. 🙂
08 июня 2009 года
54 / / 04.06.2008
08 июня 2009 года
4.5K / / 09.08.2005
Кто знает, имеет ли объект System.Collections.Generic.List какой то предел количества элементов.
Пределом выступает количество памяти, которую возможно выделить под массив (поверх которого функционирует List). Теоретического предела нет (если не рассматривать предел адресации), практический - это размер виртуальной памяти, которую может занять процесс в ОС.
02 июля 2009 года
1.2K / / 02.05.2009
Согласен с предыдущим сообщением, но дополню:
System.Collections.Generic.List имеет свойства Count и Capacity, которые являются типом int (System.Int32). Таким образом, пределом количества элементов является значение int.MaxValue.
Количество элементов в списке Python с условиями или критериями
В этом посте мы рассмотрим, как узнать число элементов в списке Python, удовлетворяющих определенным условиям или критериям.
Если вам просто нужно найти количество конкретных элементов с списке, используйте метод .count()
>>> list_numbers = [1, 2, 2, 5, 5, 7, 4, 2, 1] >>> print(list_numbers.count(2)) 3Существует несколько способов такого подсчета, и мы изучим каждый из них с помощью примеров. Итак, давайте начнем.
1. Использование цикла for для подсчета в списке Python
В этом фрагменте кода мы используем цикл for для подсчета элементов списка Python, удовлетворяющих условиям или критериям. Мы перебираем каждый элемент списка и проверяем условие, если оно истинно, то мы увеличиваем счетчик на 1. Это простой процесс сопоставления и подсчета для получения интересующего нас количества.
list_numbers = [78, 99, 66, 44, 50, 30, 45, 15, 25, 20] count = 0 for item in list_numbers: if item%5 == 0: count += 1 print("количество элементов списка, удовлетворяющих заданному условию:", count)количество элементов списка, удовлетворяющих заданному условию: 6
2. Применение len() со списковыми включениями для подсчета в списке Python
В представленном ниже фрагменте кода, мы используем списковые включения (list comprehension), чтобы создать новый список, элементы которого соответствует заданному условию, после чего мы получаем длину собранного списка. Это намного легче понять на примере, поэтому давайте перейдем к нему.
list_numbers = [78, 99, 66, 44, 50, 30, 45, 15, 25, 20] element_count = len([item for item in list_numbers if item%5 == 0]) print( "количество элементов списка, удовлетворяющих заданному условию:", element_count )количество элементов списка, удовлетворяющих заданному условию: 6
Подсчет ненулевых элементов
В этом примере мы находим общее количество ненулевых элементов. Чтобы узнать число нулевых членов списка, мы можем просто изменить условие на if item == 0 .
list_numbers = [78, 99, 66, 44, 50, 30, 45, 0, 0, 0] element_count = len([item for item in list_numbers if item != 0]) print( "количество элементов списка, удовлетворяющих заданному условию:", element_count )количество элементов списка, удовлетворяющих заданному условию: 7
3. sum() и выражение-генератор для подсчета в списке Python
В этом примере кода мы используем sum() с генераторным выражением. Каждый элемент списка проходит проверку условием и для тех элементов, которые ему удовлетворяют, возвращается значение True . Метод sum() в свою очередь подсчитывает общее число истинных значений.
list_numbers = [78, 99, 66, 44, 50, 30, 45, 15, 25, 20] count = 0 count = sum(True for i in list_numbers if i % 5 == 0) print( "количество элементов списка, удовлетворяющих заданному условию:", count )количество элементов списка, удовлетворяющих заданному условию: 6
4. sum() и map() для подсчета элементов списка Python с условиями или критериями
Функция map(fun, iterable) принимает два аргумента: итерируемый объект (это может быть строка, кортеж, список или словарь) и функцию, которая применяется к каждому его элементу, — и возвращает map-объект (итератор). Для применения одной функции внутри другой идеально подходит лямбда-функция. Таким образом, map() примет первый аргумент в виде лямбда-функции.
Здесь sum() используется с функцией map() , чтобы получить количество всех элементов списка, которые делятся на 5.
Давайте разберемся на примере, в котором переданная лямбда-функция предназначена для фильтрации членов списка, не кратных 5.
list_numbers = [78, 99, 66, 44, 50, 30, 45, 15, 25, 20] count = 0 count = sum(map(lambda item: item % 5 == 0, list_numbers)) print( "количество элементов списка, удовлетворяющих заданному условию:", count )количество элементов списка, удовлетворяющих заданному условию: 6
5. reduce() с лямбда-функцией для подсчета элементов списка Python с условием или критериями
Lambda — это анонимная (без имени) функция, которая может принимать много параметров, но тело функции должно содержать только одно выражение. Лямбда-функции чаще всего применяют для передачи в качестве аргументов в другие функции или для написания более лаконичного кода. В этом примере мы собираемся использовать функции sum() , map() и reduce() для подсчета элементов в списке, которые делятся на 5.
Приведенный ниже код наглядно демонстрирует это.
from functools import reduce list_numbers = [78, 99, 66, 44, 50, 30, 45, 15, 25, 20] result_count = reduce( lambda count, item: count + (item % 5 == 0), list_numbers, 0 ) print( "количество элементов списка, удовлетворяющих заданному условию:", result_count )количество элементов списка, удовлетворяющих заданному условию: 6
Надеюсь, что вы узнали о различных подходах к подсчету элементов в списке Python с помощью условия или критериев для фильтрации данных.