Як я можу порахувати кількість елементів списку?


1529

З огляду на елемент, як я можу порахувати його виникнення у списку в Python?

Відповіді:


1852

Якщо ви хочете лише один номер, використовуйте countметод:

>>> [1, 2, 3, 4, 1, 4, 1].count(1)
3

Не використовуйте це, якщо ви хочете порахувати кілька предметів. Виклик countу циклі вимагає окремого проходження списку для кожного countдзвінка, що може бути катастрофічно для продуктивності. Якщо ви хочете порахувати всі предмети, а то й просто декілька предметів, використовуйте Counter, як пояснено в інших відповідях.


6
mylist = [1,7,7,7,3,9,9,9,7,9,10,0] print sorted(set([i for i in mylist if mylist.count(i)>2]))
cpp-coder

1745

Використовуйте, Counterякщо ви використовуєте Python 2.7 або 3.x і вам потрібно кількість входів для кожного елемента:

>>> from collections import Counter
>>> z = ['blue', 'red', 'blue', 'yellow', 'blue', 'red']
>>> Counter(z)
Counter({'blue': 3, 'red': 2, 'yellow': 1})

2
Я виявив, що при використанні цього багато (якщо говорити про мільйони струн), це дуже повільно через його дзвінки до isinstance. Отже, якщо ви впевнені в даних, з якими ви працюєте, може бути краще написати спеціальну функцію без перевірки типу та примірника.
Брам Ванрой

2
@BramVanroy: Що isinstanceдзвонить? Навіть при мільйонах рядків виклик Counterвключає лише один isinstanceвиклик, щоб перевірити, чи є його аргументом відображення. Ви, швидше за все, неправильно оцінювали, що їсте весь свій час.
user2357112 підтримує Моніку

Ви неправильно трактували, що я мав на увазі: Лічильник перевіряє типи ваших даних, перш ніж створює лічильник. Це займає відносно багато часу, і якщо ви знаєте тип своїх даних заздалегідь. Якщо ви подивитесь на метод оновлення лічильника, ви побачите, що він повинен пройти три if-заяви, перш ніж робити щось. Якщо ви часто зателефонували до оновлення, це швидко збільшується. Коли ви маєте контроль над своїми даними та знаєте, що введення дійсно буде ітерабельним, ви можете пропустити перші два перевірки. Як я вже говорив, це я помітив лише під час роботи з мільйонами оновлень, тому це крайній випадок.
Брам Ванрой

2
@BramVanroy: Якщо ви виконуєте мільйони оновлень, а не просто рахуєте мільйони струн, це вже інша історія. CounterНамагання з оптимізації в Росії перейшли до підрахунку великих ітерабелів, а не до підрахунку багатьох ітерабелів. Підрахунок мільйона рядкових ітерабельних піде швидше, Counterніж при ручній реалізації. Якщо ви хочете зателефонувати updateз багатьма ітерабелями, ви, можливо, зможете пришвидшити речі, об’єднавши їх в один ітерабельний itertools.chain.
user2357112 підтримує Моніку

262

Підрахунок подій одного елемента в списку

Для підрахунку подій лише одного елемента списку, який ви можете використовувати count()

>>> l = ["a","b","b"]
>>> l.count("a")
1
>>> l.count("b")
2

Підрахунок подій усіх елементів у списку також відомий як "підрахунок" списку або створення лічильника підрахунків.

Підрахунок усіх елементів із кількістю ()

Для підрахунку подій елементів в lодному можна просто використати розуміння списку та count()метод

[[x,l.count(x)] for x in set(l)]

(або аналогічно зі словником dict((x,l.count(x)) for x in set(l)))

Приклад:

>>> l = ["a","b","b"]
>>> [[x,l.count(x)] for x in set(l)]
[['a', 1], ['b', 2]]
>>> dict((x,l.count(x)) for x in set(l))
{'a': 1, 'b': 2}

Підрахунок всіх елементів за допомогою лічильника ()

Крім того, є швидший Counterклас з collectionsбібліотеки

Counter(l)

Приклад:

>>> l = ["a","b","b"]
>>> from collections import Counter
>>> Counter(l)
Counter({'b': 2, 'a': 1})

Наскільки швидше лічильник?

Я перевірив, наскільки швидше Counterвідбувається розбір списків. Я спробував обидва способи з кількома значеннями, nі виявляється, що Counterце швидше постійним коефіцієнтом приблизно 2.

Ось сценарій, який я використав:

from __future__ import print_function
import timeit

t1=timeit.Timer('Counter(l)', \
                'import random;import string;from collections import Counter;n=1000;l=[random.choice(string.ascii_letters) for x in range(n)]'
                )

t2=timeit.Timer('[[x,l.count(x)] for x in set(l)]',
                'import random;import string;n=1000;l=[random.choice(string.ascii_letters) for x in range(n)]'
                )

print("Counter(): ", t1.repeat(repeat=3,number=10000))
print("count():   ", t2.repeat(repeat=3,number=10000)

І вихід:

Counter():  [0.46062711701961234, 0.4022796869976446, 0.3974247490405105]
count():    [7.779430688009597, 7.962715800967999, 8.420845870045014]

32
Counterце спосіб швидше для великих списків. Методом розуміння списку є O (n ^ 2), Counterмає бути O (n).
fhucho

20
Лічильник не швидший на коефіцієнт 2, Лічильник швидший на коефіцієнт n (O (n ^ 2) проти O (n)).
Martijn Pieters

Я виявив, що при використанні цього багато (якщо говорити про мільйони струн), це дуже повільно через його дзвінки до isinstance. Отже, якщо ви впевнені в даних, з якими ви працюєте, може бути краще написати спеціальну функцію без перевірки типу та примірника.
Брам Ванрой

66

Ще один спосіб отримати кількість зустрічей кожного елемента в словнику:

dict((i, a.count(i)) for i in a)

49
це схоже на один з конструктів, які я часто придумую в розпал битви, але він буде проходити через тривалість часу (а), що означає квадратичну складність виконання (оскільки кожен пробіг знову залежить від len (a)).
Nicolas78

5
dict ((i, a.count (i)) для i у множині (a)) буде правильнішим та швидшим?
hugo24

6
@ hugo24: Трохи, але в гіршому випадку це не буде асимптотично швидше; це займе n * (number of different items)операції, не рахуючи часу, необхідного для створення набору. Використовувати collections.Counterнасправді набагато краще.
Клімент

дуже пізно до партії, але не слід за цим кодом видавати помилку, якщо список містить більше одного екземпляра i, тому що він спробує ввести в словник декілька ключів однакового значення. dict((i, a.count(i)) for i in a)
rp1


45

З огляду на елемент, як я можу порахувати його виникнення у списку в Python?

Ось приклад списку:

>>> l = list('aaaaabbbbcccdde')
>>> l
['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'e']

list.count

Там є list.countметод

>>> l.count('b')
4

Це добре працює для будь-якого списку. Також кортежі мають цей спосіб:

>>> t = tuple('aabbbffffff')
>>> t
('a', 'a', 'b', 'b', 'b', 'f', 'f', 'f', 'f', 'f', 'f')
>>> t.count('f')
6

collections.Counter

А далі є колекції. Ви можете скинути будь-який ітерабельний у лічильник, а не лише у список, і лічильник збереже структуру даних про кількість елементів.

Використання:

>>> from collections import Counter
>>> c = Counter(l)
>>> c['b']
4

Лічильники базуються на словниках Python, їхні клавіші - це елементи, тому ключі повинні бути перебірливими. Вони в основному схожі на множини, які дозволяють вводити зайві елементи в них.

Подальше використання collections.Counter

Ви можете додавати або віднімати з ітерабелів зі свого лічильника:

>>> c.update(list('bbb'))
>>> c['b']
7
>>> c.subtract(list('bbb'))
>>> c['b']
4

І з лічильником можна виконувати також багатонабірні операції:

>>> c2 = Counter(list('aabbxyz'))
>>> c - c2                   # set difference
Counter({'a': 3, 'c': 3, 'b': 2, 'd': 2, 'e': 1})
>>> c + c2                   # addition of all elements
Counter({'a': 7, 'b': 6, 'c': 3, 'd': 2, 'e': 1, 'y': 1, 'x': 1, 'z': 1})
>>> c | c2                   # set union
Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1, 'y': 1, 'x': 1, 'z': 1})
>>> c & c2                   # set intersection
Counter({'a': 2, 'b': 2})

Чому б не панди?

Ще одна відповідь пропонує:

Чому б не використовувати панди?

Панди - це загальна бібліотека, але її немає в стандартній бібліотеці. Додавання його як вимоги нетривіально.

Є вбудовані рішення для цього випадку використання як в самому об'єкті списку, так і в стандартній бібліотеці.

Якщо ваш проект вже не вимагає панди, було б нерозумно ставити його вимогою саме до цієї функціональності.


4
Хоча "чому б не Pandas" підходить, воно, ймовірно, повинно супроводжуватися "коли використовувати NumPy", тобто для великих числових масивів. Вирішальним фактором є не лише обмеження проекту, але ефективність пам'яті з NumPy стає очевидною при великих даних.
jpp

Дякуємо, що згадували про панду / тощо як про серйозну залежність Деякі з цих пакунків мають негативні побічні ефекти. Тож додавання цих активів для тривіальних потреб може коштувати багато часу і $. Особисто я зазнав, що Numpy та SciPi додають 30 хв до нашого конвеєра CI, і для правильного кешування пакета знадобилося кілька днів. Чудові пакети, але іноді є приховані витрати. + +1
Марк

36

Я порівнював усі запропоновані рішення (і кілька нових) з perfplot ( мій невеликий проект).

Підрахунок одного елемента

Для досить великих масивів виявляється, що

numpy.sum(numpy.array(a) == 1) 

трохи швидше, ніж інші рішення.

введіть тут опис зображення

Підрахунок всіх предметів

Як було встановлено раніше ,

numpy.bincount(a)

це те, що ти хочеш.

введіть тут опис зображення


Код для відтворення сюжетів:

from collections import Counter
from collections import defaultdict
import numpy
import operator
import pandas
import perfplot


def counter(a):
    return Counter(a)


def count(a):
    return dict((i, a.count(i)) for i in set(a))


def bincount(a):
    return numpy.bincount(a)


def pandas_value_counts(a):
    return pandas.Series(a).value_counts()


def occur_dict(a):
    d = {}
    for i in a:
        if i in d:
            d[i] = d[i]+1
        else:
            d[i] = 1
    return d


def count_unsorted_list_items(items):
    counts = defaultdict(int)
    for item in items:
        counts[item] += 1
    return dict(counts)


def operator_countof(a):
    return dict((i, operator.countOf(a, i)) for i in set(a))


perfplot.show(
    setup=lambda n: list(numpy.random.randint(0, 100, n)),
    n_range=[2**k for k in range(20)],
    kernels=[
        counter, count, bincount, pandas_value_counts, occur_dict,
        count_unsorted_list_items, operator_countof
        ],
    equality_check=None,
    logx=True,
    logy=True,
    )

2.

from collections import Counter
from collections import defaultdict
import numpy
import operator
import pandas
import perfplot


def counter(a):
    return Counter(a)


def count(a):
    return dict((i, a.count(i)) for i in set(a))


def bincount(a):
    return numpy.bincount(a)


def pandas_value_counts(a):
    return pandas.Series(a).value_counts()


def occur_dict(a):
    d = {}
    for i in a:
        if i in d:
            d[i] = d[i]+1
        else:
            d[i] = 1
    return d


def count_unsorted_list_items(items):
    counts = defaultdict(int)
    for item in items:
        counts[item] += 1
    return dict(counts)


def operator_countof(a):
    return dict((i, operator.countOf(a, i)) for i in set(a))


perfplot.show(
    setup=lambda n: list(numpy.random.randint(0, 100, n)),
    n_range=[2**k for k in range(20)],
    kernels=[
        counter, count, bincount, pandas_value_counts, occur_dict,
        count_unsorted_list_items, operator_countof
        ],
    equality_check=None,
    logx=True,
    logy=True,
    )

7
numpy.bincount () працюватиме лише для списків з елементами int.
Мукаррам-паша

35

Якщо ви хочете порахувати всі значення одразу, ви можете зробити це дуже швидко, використовуючи nummy масиви та bincountнаступним чином

import numpy as np
a = np.array([1, 2, 3, 4, 1, 4, 1])
np.bincount(a)

що дає

>>> array([0, 3, 1, 1, 2])

19

Якщо ви можете скористатися pandas, тоді value_countsє для порятунку.

>>> import pandas as pd
>>> a = [1, 2, 3, 4, 1, 4, 1]
>>> pd.Series(a).value_counts()
1    3
4    2
3    1
2    1
dtype: int64

Він автоматично сортує результат на основі частоти.

Якщо ви хочете, щоб результат був у списку, виконайте наступні дії

>>> pd.Series(a).value_counts().reset_index().values.tolist()
[[1, 3], [4, 2], [3, 1], [2, 1]]

Однак панди мають великі накладні витрати, тому це найповільніше рішення з невеликою кількістю даних. stackoverflow.com/a/46195192/125507
ендоліти

14

Чому б не використовувати Pandas?

import pandas as pd

l = ['a', 'b', 'c', 'd', 'a', 'd', 'a']

# converting the list to a Series and counting the values
my_count = pd.Series(l).value_counts()
my_count

Вихід:

a    3
d    2
b    1
c    1
dtype: int64

Якщо ви шукаєте відлік певного елемента, скажімо , спробуйте:

my_count['a']

Вихід:

3

13

Я мав цю проблему сьогодні і розробив власне рішення, перш ніж я подумав перевірити ТАК. Це:

dict((i,a.count(i)) for i in a)

дійсно, дуже повільно для великих списків. Моє рішення

def occurDict(items):
    d = {}
    for i in items:
        if i in d:
            d[i] = d[i]+1
        else:
            d[i] = 1
return d

насправді трохи швидше, ніж рішення Counter, принаймні для Python 2.7.


1
Лічильник сортує записи, а ваші - ні, отже, різниця в швидкості (Правда на момент написання, не впевнений, чи було це, коли ви писали відповідь. Все-таки це може бути актуальним для того, щоб хтось прокручував вниз.)
chaosflaws

3
Лічильник в Python 2 був трохи повільним, так. Однак він використовує оптимізований C код для підрахунку в Python 3, але тепер б'є ваш цикл легко.
Martijn Pieters

12
# Python >= 2.6 (defaultdict) && < 2.7 (Counter, OrderedDict)
from collections import defaultdict
def count_unsorted_list_items(items):
    """
    :param items: iterable of hashable items to count
    :type items: iterable

    :returns: dict of counts like Py2.7 Counter
    :rtype: dict
    """
    counts = defaultdict(int)
    for item in items:
        counts[item] += 1
    return dict(counts)


# Python >= 2.2 (generators)
def count_sorted_list_items(items):
    """
    :param items: sorted iterable of items to count
    :type items: sorted iterable

    :returns: generator of (item, count) tuples
    :rtype: generator
    """
    if not items:
        return
    elif len(items) == 1:
        yield (items[0], 1)
        return
    prev_item = items[0]
    count = 1
    for item in items[1:]:
        if prev_item == item:
            count += 1
        else:
            yield (prev_item, count)
            count = 1
            prev_item = item
    yield (item, count)
    return


import unittest
class TestListCounters(unittest.TestCase):
    def test_count_unsorted_list_items(self):
        D = (
            ([], []),
            ([2], [(2,1)]),
            ([2,2], [(2,2)]),
            ([2,2,2,2,3,3,5,5], [(2,4), (3,2), (5,2)]),
            )
        for inp, exp_outp in D:
            counts = count_unsorted_list_items(inp) 
            print inp, exp_outp, counts
            self.assertEqual(counts, dict( exp_outp ))

        inp, exp_outp = UNSORTED_WIN = ([2,2,4,2], [(2,3), (4,1)])
        self.assertEqual(dict( exp_outp ), count_unsorted_list_items(inp) )


    def test_count_sorted_list_items(self):
        D = (
            ([], []),
            ([2], [(2,1)]),
            ([2,2], [(2,2)]),
            ([2,2,2,2,3,3,5,5], [(2,4), (3,2), (5,2)]),
            )
        for inp, exp_outp in D:
            counts = list( count_sorted_list_items(inp) )
            print inp, exp_outp, counts
            self.assertEqual(counts, exp_outp)

        inp, exp_outp = UNSORTED_FAIL = ([2,2,4,2], [(2,3), (4,1)])
        self.assertEqual(exp_outp, list( count_sorted_list_items(inp) ))
        # ... [(2,2), (4,1), (2,1)]

2
@plaes: Як так? Якщо під "підприємництвом" ви маєте на увазі "документально підтверджені документи" під час підготовки до анотацій Py3k, я згоден.
Уес Тернер

1
Це чудовий приклад, оскільки я розвиваюсь в основному в 2.7, але мушу мати шлях міграції до 2,4.
Адам Льюїс

9

Нижче наведено три рішення:

Найшвидше використовується цикл for і зберігає його в Dict.

import time
from collections import Counter


def countElement(a):
    g = {}
    for i in a:
        if i in g: 
            g[i] +=1
        else: 
            g[i] =1
    return g


z = [1,1,1,1,2,2,2,2,3,3,4,5,5,234,23,3,12,3,123,12,31,23,13,2,4,23,42,42,34,234,23,42,34,23,423,42,34,23,423,4,234,23,42,34,23,4,23,423,4,23,4]


#Solution 1 - Faster
st = time.monotonic()
for i in range(1000000):
    b = countElement(z)
et = time.monotonic()
print(b)
print('Simple for loop and storing it in dict - Duration: {}'.format(et - st))

#Solution 2 - Fast
st = time.monotonic()
for i in range(1000000):
    a = Counter(z)
et = time.monotonic()
print (a)
print('Using collections.Counter - Duration: {}'.format(et - st))

#Solution 3 - Slow
st = time.monotonic()
for i in range(1000000):
    g = dict([(i, z.count(i)) for i in set(z)])
et = time.monotonic()
print(g)
print('Using list comprehension - Duration: {}'.format(et - st))

Результат

#Solution 1 - Faster
{1: 4, 2: 5, 3: 4, 4: 6, 5: 2, 234: 3, 23: 10, 12: 2, 123: 1, 31: 1, 13: 1, 42: 5, 34: 4, 423: 3}
Simple for loop and storing it in dict - Duration: 12.032000000000153
#Solution 2 - Fast
Counter({23: 10, 4: 6, 2: 5, 42: 5, 1: 4, 3: 4, 34: 4, 234: 3, 423: 3, 5: 2, 12: 2, 123: 1, 31: 1, 13: 1})
Using collections.Counter - Duration: 15.889999999999418
#Solution 3 - Slow
{1: 4, 2: 5, 3: 4, 4: 6, 5: 2, 34: 4, 423: 3, 234: 3, 42: 5, 12: 2, 13: 1, 23: 10, 123: 1, 31: 1}
Using list comprehension - Duration: 33.0

9

Полічити всі елементи з itertools.groupby()

Антогера можливість отримати підрахунок усіх елементів у списку може бути за допомогою itertools.groupby().

З підрахунками "дублікат"

from itertools import groupby

L = ['a', 'a', 'a', 't', 'q', 'a', 'd', 'a', 'd', 'c']  # Input list

counts = [(i, len(list(c))) for i,c in groupby(L)]      # Create value-count pairs as list of tuples 
print(counts)

Повертається

[('a', 3), ('t', 1), ('q', 1), ('a', 1), ('d', 1), ('a', 1), ('d', 1), ('c', 1)]

Зауважте, як він поєднав перших трьох aяк першу групу, а інші групи aприсутні далі в списку. Це відбувається тому, що список введення Lне був відсортований. Іноді це може бути користю, якщо групи насправді мають бути окремими.

З унікальними підрахунками

Якщо потрібні унікальні підрахунки груп, просто сортуйте список введення:

counts = [(i, len(list(c))) for i,c in groupby(sorted(L))]
print(counts)

Повертається

[('a', 5), ('c', 1), ('d', 2), ('q', 1), ('t', 1)]

Примітка. Для створення унікальних підрахунків багато інших відповідей надають більш простий і читабельний код порівняно з groupbyрішенням. Але показано тут, щоб провести паралель прикладу підрахунку дублікатів.


7

Було запропоновано використовувати номер рахунку numpy , однак він працює лише для 1d масивів з невід'ємними цілими числами . Крім того, отриманий масив може бути заплутаним (він містить випадки виникнення цілих чисел від min до max вихідного списку і встановлює 0 відсутніх цілих чисел).

Кращий спосіб зробити це з numpy - використовувати унікальну функцію з атрибутом, return_countsвстановленим True. Він повертає кортеж з масивом унікальних значень та масивом зустрічей кожного унікального значення.

# a = [1, 1, 0, 2, 1, 0, 3, 3]
a_uniq, counts = np.unique(a, return_counts=True)  # array([0, 1, 2, 3]), array([2, 3, 1, 2]

і тоді ми можемо їх поєднати як

dict(zip(a_uniq, counts))  # {0: 2, 1: 3, 2: 1, 3: 2}

Він також працює з іншими типами даних та "2d списками", наприклад

>>> a = [['a', 'b', 'b', 'b'], ['a', 'c', 'c', 'a']]
>>> dict(zip(*np.unique(a, return_counts=True)))
{'a': 3, 'b': 3, 'c': 2}

6

Для підрахунку кількості різноманітних елементів, що мають загальний тип:

li = ['A0','c5','A8','A2','A5','c2','A3','A9']

print sum(1 for el in li if el[0]=='A' and el[1] in '01234')

дає

3 , а не 6


4

Хоча це дуже давнє питання, але оскільки я не знайшов жодного вкладиша, я зробив його.

# original numbers in list
l = [1, 2, 2, 3, 3, 3, 4]

# empty dictionary to hold pair of number and its count
d = {}

# loop through all elements and store count
[ d.update( {i:d.get(i, 0)+1} ) for i in l ]

print(d)

Не використовуйте розуміння списку для побічних ефектів. Дивіться: Чи Pythonic використовувати розуміння списку лише для побічних ефектів?
Георгій

3

Ви також можете використовувати countOfметод вбудованого модуля operator.

>>> import operator
>>> operator.countOf([1, 2, 3, 4, 1, 4, 1], 1)
3

1
Як countOfце реалізується? Як воно порівнюється з більш очевидним list.count(які переваги від реалізації С)? Чи є якісь переваги?
Chris_Rands

2

Може бути не найефективнішим, потрібен додатковий пропуск для видалення дублікатів.

Функціональна реалізація:

arr = np.array(['a','a','b','b','b','c'])
print(set(map(lambda x  : (x , list(arr).count(x)) , arr)))

повертає:

{('c', 1), ('b', 3), ('a', 2)}

або повернутися як dict:

print(dict(map(lambda x  : (x , list(arr).count(x)) , arr)))

повертає:

{'b': 3, 'c': 1, 'a': 2}

1
sum([1 for elem in <yourlist> if elem==<your_value>])

Це поверне кількість випадків вашої значення


1

Я б скористався filter()прикладом Лукаша:

>>> lst = [1, 2, 3, 4, 1, 4, 1]
>>> len(filter(lambda x: x==1, lst))
3

0

якщо ви хочете отримати ряд випадків для конкретного елемента:

>>> from collections import Counter
>>> z = ['blue', 'red', 'blue', 'yellow', 'blue', 'red']
>>> single_occurrences = Counter(z)
>>> print(single_occurrences.get("blue"))
3
>>> print(single_occurrences.values())
dict_values([3, 2, 1])

-1
def countfrequncyinarray(arr1):
    r=len(arr1)
    return {i:arr1.count(i) for i in range(1,r+1)}
arr1=[4,4,4,4]
a=countfrequncyinarray(arr1)
print(a)

3
Хоча цей код може відповісти на питання, надаючи додатковий контекст щодо того, чому та / або як цей код відповідає на питання, покращує його довгострокове значення.
Олексій Рябов

-1
l2=[1,"feto",["feto",1,["feto"]],['feto',[1,2,3,['feto']]]]
count=0
 def Test(l):   
        global count 
        if len(l)==0:
             return count
        count=l.count("feto")
        for i in l:
             if type(i) is list:
                count+=Test(i)
        return count   
    print(Test(l2))

це буде рекурсивно рахувати або шукати елемент у списку, навіть якщо він є у списку списків


я не знаю, чому хтось просто вниз голосує на відповідь, і це корисно
Мохамед Фаталла
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.