web-dev-qa-db-fra.com

python: obtenir le nombre d'éléments de la liste (séquence) avec certaines conditions

En supposant que j'ai une liste avec un grand nombre d'éléments.

l = [ 1, 4, 6, 30, 2, ... ]

Je veux obtenir le nombre d'éléments de cette liste, où un élément doit remplir certaines conditions. Ma première pensée fut:

count = len([i for i in l if my_condition(l)])

Mais si la liste filtrée par my_condition () contient également un grand nombre d'éléments, je pense que créer une nouvelle liste avec un résultat filtré n'est qu'un gaspillage de mémoire. Pour plus d'efficacité, à mon humble avis, l'appel ci-dessus ne peut pas être meilleur que:

count = 0
for i in l:
    if my_condition(l):
        count += 1

Existe-t-il un moyen fonctionnel d'obtenir le nombre d'éléments satisfaisant certaines conditions sans générer de liste temporaire?

Merci d'avance.

66
cinsk

Vous pouvez utiliser un expression génératrice :

>>> l = [1, 3, 7, 2, 6, 8, 10]
>>> sum(1 for i in l if i % 4 == 3)
2

ou même

>>> sum(i % 4 == 3 for i in l)
2

qui utilise le fait que int(True) == 1.

Vous pouvez également utiliser itertools.imap (Python 2) ou simplement map (python 3):

>>> def my_condition(x):
...     return x % 4 == 3
... 
>>> sum(map(my_condition, l))
2
87
DSM

Vous voulez un compréhension du générateur plutôt qu'une liste ici.

Par exemple,

l = [1, 4, 6, 7, 30, 2]

def my_condition(x):
    return x > 5 and x < 20

print sum(1 for x in l if my_condition(x))
# -> 2
print sum(1 for x in range(1000000) if my_condition(x))
# -> 14

Ou utiliser itertools.imap (bien que je pense que les expressions explicites de liste et de générateur ont l’air un peu plus pythoniques).

Notez que, bien que ce ne soit pas évident à partir de l'exemple sum, vous pouvez bien composer les compréhensions des générateurs. Par exemple,

inputs = xrange(1000000)      # In Python 3 and above, use range instead of xrange
odds = (x for x in inputs if x % 2)  # Pick odd numbers
sq_inc = (x**2 + 1 for x in odds)    # Square and add one
print sum(x/2 for x in sq_inc)       # Actually evaluate each one
# -> 83333333333500000

La bonne chose à propos de cette technique est que vous pouvez spécifier des étapes conceptuellement séparées dans le code sans forcer l’évaluation et le stockage en mémoire jusqu’à l’évaluation du résultat final.

17
JohnJ

vous pourriez faire quelque chose comme:

l = [1,2,3,4,5,..]
count = sum(1 for i in l if my_condition(i))

qui ajoute juste 1 pour chaque élément qui remplit la condition.

6
Jsdodgers

Ceci peut aussi être fait en utilisant reduce si vous préférez la programmation fonctionnelle

reduce(lambda count, i: count + my_condition(i), l, 0)

De cette façon, vous ne faites qu'un seul passage et aucune liste intermédiaire n'est générée.

6
Will
from itertools import imap
sum(imap(my_condition, l))
1
kkonrad

J'ai eu un problème similaire et le résoudre en utilisant des générateurs.

Je pense aussi que cette question peut vous aider: Filtrage de liste: compréhension de la liste par rapport au filtre lambda +

0
darkless