395 votes

Comment diviser une liste en fonction d'une condition ?

Quelle est la meilleure façon, à la fois esthétiquement et du point de vue des performances, de diviser une liste d'éléments en plusieurs listes sur la base d'une condition ? L'équivalent de :

good = [x for x in mylist if x in goodvals]
bad  = [x for x in mylist if x not in goodvals]

Existe-t-il une manière plus élégante de procéder ?

Voici le cas d'utilisation réel, pour mieux expliquer ce que j'essaie de faire :

# files looks like: [ ('file1.jpg', 33L, '.jpg'), ('file2.avi', 999L, '.avi'), ... ]
IMAGE_TYPES = ('.jpg','.jpeg','.gif','.bmp','.png')
images = [f for f in files if f[2].lower() in IMAGE_TYPES]
anims  = [f for f in files if f[2].lower() not in IMAGE_TYPES]

9 votes

J'ai atterri ici à la recherche d'un moyen d'avoir une condition dans l'instruction set builder, votre question a répondu à la mienne :)

8 votes

diviser est une description malheureuse de cette opération, puisqu'elle a déjà une signification spécifique en ce qui concerne les chaînes Python. Je pense que diviser est un terme plus précis (ou du moins moins surchargé dans le contexte des itérables Python) pour décrire cette opération. J'ai atterri ici à la recherche d'un équivalent de liste de str.split() , à diviser la liste en une collection ordonnée de sous-listes consécutives. Par exemple split([1,2,3,4,5,3,6], 3) -> ([1,2],[4,5],[6]) frente a diviser les éléments d'une liste par catégorie.

0 votes

Discussion du même sujet sur python-list.

0voto

Anders Eurenius Points 2976

Si vous insistez sur l'intelligence, vous pourriez prendre la solution de Winden et faire preuve d'un peu d'intelligence fallacieuse :

def splay(l, f, d=None):
  d = d or {}
  for x in l: d.setdefault(f(x), []).append(x)
  return d

0voto

Shikhar Mall Points 11

Parfois, vous n'aurez pas besoin de l'autre moitié de la liste. Par exemple :

import sys
from itertools import ifilter

trustedPeople = sys.argv[1].split(',')
newName = sys.argv[2]

myFriends = ifilter(lambda x: x.startswith('Shi'), trustedPeople)

print '%s is %smy friend.' % (newName, newName not in myFriends 'not ' or '')

0voto

Shreyas Points 35

Il y a déjà pas mal de solutions ici, mais une autre façon de faire serait -

anims = []
images = [f for f in files if (lambda t: True if f[2].lower() in IMAGE_TYPES else anims.append(t) and False)(f)]

N'itère sur la liste qu'une seule fois, et me semble un peu plus pythonique et donc plus lisible.

>>> files = [ ('file1.jpg', 33L, '.jpg'), ('file2.avi', 999L, '.avi'), ('file1.bmp', 33L, '.bmp')]
>>> IMAGE_TYPES = ('.jpg','.jpeg','.gif','.bmp','.png')
>>> anims = []
>>> images = [f for f in files if (lambda t: True if f[2].lower() in IMAGE_TYPES else anims.append(t) and False)(f)]
>>> print '\n'.join([str(anims), str(images)])
[('file2.avi', 999L, '.avi')]
[('file1.jpg', 33L, '.jpg'), ('file1.bmp', 33L, '.bmp')]
>>>

0voto

Jim Witschey Points 285

J'adopterais une approche en deux temps, en séparant l'évaluation du prédicat du filtrage de la liste :

def partition(pred, iterable):
    xs = list(zip(map(pred, iterable), iterable))
    return [x[1] for x in xs if x[0]], [x[1] for x in xs if not x[0]]

Ce qui est bien, c'est qu'en termes de performances (en plus de l'évaluation des pred qu'une seule fois sur chaque membre de iterable ), c'est qu'il déplace une grande partie de la logique hors de l'interpréteur et dans un code d'itération et de mappage hautement optimisé. Cela permet d'accélérer l'itération sur de longues tables itératives, comme décrit dans la section dans cette réponse .

Sur le plan de l'expressivité, il tire parti d'idiomes expressifs tels que les compréhensions et le mappage.

0voto

kiran Points 13

Je ne sais pas si c'est une bonne approche, mais cela peut aussi être fait de cette manière.

IMAGE_TYPES = ('.jpg','.jpeg','.gif','.bmp','.png')
files = [ ('file1.jpg', 33L, '.jpg'), ('file2.avi', 999L, '.avi')]
images, anims = reduce(lambda (i, a), f: (i + [f], a) if f[2] in IMAGE_TYPES else (i, a + [f]), files, ([], []))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X