Como posso contar as ocorrências de um item da lista?


1530

Dado um item, como posso contar suas ocorrências em uma lista no Python?

Respostas:


1853

Se você deseja apenas a contagem de um item, use o countmétodo:

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

Não use isso se quiser contar vários itens. A chamada countem loop requer uma passagem separada sobre a lista para cada countchamada, o que pode ser catastrófico para o desempenho. Se você deseja contar todos os itens, ou mesmo apenas vários itens, use Counter, conforme explicado nas outras respostas.


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

1746

Use Counterse você estiver usando Python 2.7 ou 3.x e desejar o número de ocorrências para cada elemento:

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

2
Eu descobri que ao usar isso muito (falando sobre milhões de strings), é muito lento por causa de suas chamadas para isinstance. Portanto, se você tiver certeza dos dados com os quais está trabalhando, talvez seja melhor escrever uma função personalizada sem verificação de tipo e instância.
Bram Vanroy,

2
@BramVanroy: O que isinstancechama? Mesmo com milhões de strings, a chamada Counterenvolve apenas uma isinstancechamada, para verificar se o argumento é um mapeamento. Você provavelmente julgou mal o que está comendo o tempo todo.
user2357112 suporta Monica

Você interpretou mal o que eu quis dizer: O contador verifica os tipos de seus dados antes de criar o contador. Isso leva muito tempo e se você conhece o tipo de seus dados com antecedência. Se você observar o método de atualização do Counter, verá que ele precisa passar por três instruções if antes de fazer algo. Se você chamar a atualização com frequência, isso aumentará rapidamente. Quando você tem controle sobre seus dados e sabe que a entrada será realmente iterável, pule as duas primeiras verificações. Como eu disse, só notei isso ao trabalhar com milhões de atualizações, por isso é um caso extremo.
Bram Vanroy

2
@BramVanroy: Se você está executando milhões de atualizações em vez de apenas contar milhões de strings, é uma história diferente. O esforço de otimização Counterpassou a contar iteráveis ​​grandes, em vez de contar muitos iteráveis. Contar um iterável de um milhão de strings será mais rápido do Counterque com uma implementação manual. Se você quiser ligar updatecom muitas iteráveis, poderá acelerar as coisas juntando-as a uma iterável itertools.chain.
User2357112 suporta Monica

262

Contando as ocorrências de um item em uma lista

Para contar as ocorrências de apenas um item da lista, você pode usar count()

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

Contando as ocorrências de todos itens de uma lista também é conhecido como "calcular" uma lista ou criar um contador de contagem.

Contando todos os itens com count ()

Contar as ocorrências de itens em lum pode simplesmente usar uma compreensão de lista e o count()método

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

(ou similarmente com um dicionário dict((x,l.count(x)) for x in set(l)) )

Exemplo:

>>> 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}

Contando todos os itens com Counter ()

Como alternativa, há a Counterclasse mais rápida da collectionsbiblioteca

Counter(l)

Exemplo:

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

Quanto mais rápido é o contador?

Eu verifiquei o quão mais rápido Counteré para listas de cálculo. Eu tentei ambos os métodos com alguns valores de ne parece queCounter é mais rápido por um fator constante de aproximadamente 2.

Aqui está o script que eu usei:

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)

E a saída:

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

32
Counteré muito mais rápido para listas maiores. O método de compreensão da lista é O (n ^ 2), Counterdeve ser O (n).
Fhucho 11/11

20
O contador não é mais rápido por um fator de 2, o contador é mais rápido por um fator de n (O (n ^ 2) vs O (n)).
Martijn Pieters

Eu descobri que ao usar isso muito (falando sobre milhões de strings), é muito lento por causa de suas chamadas para isinstance. Portanto, se você tiver certeza dos dados com os quais está trabalhando, talvez seja melhor escrever uma função personalizada sem verificação de tipo e instância.
Bram Vanroy,

66

Outra maneira de obter o número de ocorrências de cada item, em um dicionário:

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

49
isso se parece com uma das construções que eu frequentemente desenvolvo no calor da batalha, mas será executada um tempo len (a), o que significa complexidade quadrática do tempo de execução (já que cada execução depende do len (a) novamente).
Nicolas78 10/10

5
dict ((i, a.count (i)) para i no conjunto (a)) seria mais correto e mais rápido?
Hugo24 23/08

6
@ hugo24: Um pouco, mas não será assintoticamente mais rápido no pior dos casos; levará n * (number of different items)operações, sem contar o tempo necessário para construir o conjunto. Usar collections.Counteré realmente muito melhor.
Clément

muito tarde para a parte, mas o código a seguir não emitirá um erro se uma lista contiver mais de uma instância de i, porque ela tentará inserir várias chaves do mesmo valor em um dicionário. dict((i, a.count(i)) for i in a)
Rp1


45

Dado um item, como posso contar suas ocorrências em uma lista no Python?

Aqui está uma lista de exemplos:

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

list.count

Existe o list.countmétodo

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

Isso funciona bem para qualquer lista. As tuplas também têm esse método:

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

collections.Counter

E depois há coleções. Você pode despejar qualquer iterável em um contador, não apenas em uma lista, e o contador manterá uma estrutura de dados das contagens dos elementos.

Uso:

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

Os contadores são baseados em dicionários Python; suas chaves são os elementos; portanto, as chaves precisam ser laváveis. Eles são basicamente como conjuntos que permitem elementos redundantes neles.

Uso adicional de collections.Counter

Você pode adicionar ou subtrair com iterables do seu contador:

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

E você também pode executar operações de vários conjuntos com o contador:

>>> 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})

Por que não pandas?

Outra resposta sugere:

Por que não usar pandas?

O Pandas é uma biblioteca comum, mas não está na biblioteca padrão. Adicioná-lo como um requisito não é trivial.

Existem soluções internas para esse caso de uso no próprio objeto de lista e na biblioteca padrão.

Se seu projeto ainda não requer pandas, seria tolice torná-lo um requisito apenas para esta funcionalidade.


4
Embora "por que não o Pandas" seja apropriado, provavelmente deve ser acompanhado por "quando usar o NumPy", ou seja, para grandes matrizes numéricas. O fator decisivo não são apenas as limitações do projeto, existem eficiências de memória com o NumPy que se tornam aparentes no big data.
jpp

Obrigado por mencionar o Pandas / etc como uma dependência séria. Alguns desses pacotes têm efeitos colaterais negativos. Portanto, a adição desses ativos para necessidades triviais pode custar muito tempo e US $. Pessoalmente, experimentei o Numpy e o SciPi adicionando 30 minutos ao nosso pipeline de IC e demorou dias para obter o cache do pacote corretamente. Grandes pacotes, mas às vezes há despesas ocultas. Marcado com +1
Marc

36

Comparei todas as soluções sugeridas (e algumas novas) com perfplot (um pequeno projeto meu).

Contando um item

Para matrizes grandes o suficiente, acontece que

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

é um pouco mais rápido que as outras soluções.

insira a descrição da imagem aqui

Contando tudo itens

Conforme estabelecido anteriormente ,

numpy.bincount(a)

é o que você quer.

insira a descrição da imagem aqui


Código para reproduzir as parcelas:

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 () funcionará apenas para listas com itens int.
Mukarram Pasha

35

Se você quiser contar todos os valores de uma só vez, poderá fazê-lo muito rapidamente usando matrizes numpy e da bincountseguinte maneira

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

que dá

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

19

Se você pode usar pandas, então value_countsexiste para resgatar.

>>> 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

Também classifica automaticamente o resultado com base na frequência.

Se você deseja que o resultado esteja em uma lista de listas, faça o seguinte:

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

os pandas têm muita sobrecarga, portanto, é a solução mais lenta com pequenas quantidades de dados. stackoverflow.com/a/46195192/125507
endolith

14

Por que não usar 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

Resultado:

a    3
d    2
b    1
c    1
dtype: int64

Se você estiver procurando uma contagem de um elemento específico, diga a , tente:

my_count['a']

Resultado:

3

13

Hoje eu tive esse problema e rolei minha própria solução antes de pensar em verificar o SO. Este:

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

é muito, muito lento para grandes listas. Minha solução

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

é realmente um pouco mais rápido que a solução Counter, pelo menos para o Python 2.7.


1
Contador classifica as entradas enquanto o seu não, daí a diferença de velocidade (. É verdade, no momento da escrita, não tenho certeza se era quando você escreveu a resposta Ainda assim, pode ser relevante para alguém rolagem para baixo.)
chaosflaws

3
O contador no Python 2 foi um pouco lento, sim. No entanto, ele usa código otimizado em C para fazer a contagem no Python 3 e agora supera seu loop com facilidade.
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: Como assim? Se por 'empreendedor', você quer dizer "documentado" em preparação para anotações em Py3k, eu concordo.
Wes Turner

1
Este é um ótimo exemplo, pois estou desenvolvendo principalmente no 2.7, mas preciso ter caminhos de migração para o 2.4.
Adam Lewis

9

Abaixo estão as três soluções:

O mais rápido é usar um loop for e armazená-lo em um 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))

Resultado

#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

Contagem de todos os elementos com itertools.groupby()

Outra possibilidade de obter a contagem de todos os elementos da lista pode ser por meio de itertools.groupby() .

Com contagens "duplicadas"

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)

Devoluções

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

Observe como ele combinou os três primeiros acomo o primeiro grupo, enquanto outros grupos de aestão presentes mais abaixo na lista. Isso acontece porque a lista de entrada Lnão foi classificada. Às vezes, isso pode ser um benefício se os grupos forem de fato separados.

Com contagens únicas

Se desejar contagens únicas de grupos, basta classificar a lista de entradas:

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

Devoluções

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

Nota: Para criar contagens exclusivas, muitas das outras respostas fornecem código mais fácil e mais legível em comparação com a groupbysolução. Mas é mostrado aqui para desenhar um paralelo ao exemplo de contagem duplicada.


7

Foi sugerido o uso da contagem de números de um número , no entanto, ele funciona apenas para matrizes 1d com números inteiros não negativos . Além disso, a matriz resultante pode ser confusa (contém as ocorrências dos números inteiros de min a max da lista original e define como 0 os números inteiros ausentes).

Uma maneira melhor de fazer isso com numpy é usar a função exclusiva com o atributo return_countsdefinido como True. Retorna uma tupla com uma matriz dos valores exclusivos e uma matriz das ocorrências de cada valor exclusivo.

# 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]

e então podemos emparelhá-los como

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

Também funciona com outros tipos de dados e "listas 2d", por exemplo

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

6

Para contar o número de diversos elementos com um tipo comum:

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 , não 6



3

Você também pode usar o countOfmétodo de um módulo interno operator.

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

1
Como countOfé implementado? Como ele se compara ao mais óbvio list.count(que se beneficia da implementação C)? Existem vantagens?
23417 Chris_Rands

2

Pode não ser o mais eficiente, requer uma passagem extra para remover duplicatas.

Implementação funcional:

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

retorna:

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

ou retorne como dict:

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

retorna:

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

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

Isso retornará a quantidade de ocorrências do seu_valor


1

Eu usaria filter(), pegue o exemplo de Lukasz:

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

0

se você deseja várias ocorrências para o elemento específico:

>>> 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
Embora esse código possa responder à pergunta, fornecer um contexto adicional a respeito de por que e / ou como esse código responde à pergunta melhora seu valor a longo prazo.
Alex Riabov 07/07/19

-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))

isso contará recursivamente ou procurará o item na lista, mesmo que ele esteja na lista de listas


Eu não sei por que alguém apenas baixa uma resposta e é completamente útil
Mohamed Fathallah 17/04
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.