What's the best way, both aesthetically and from a performance perspective, to split a list of items into multiple lists based on a conditional? The equivalent of:
good = [x for x in mylist if x in goodvals] bad = [x for x in mylist if x not in goodvals]
Is there a more elegant way to do this?
Here's the actual use case, to better explain what I'm trying to do:
# 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]
split() , to split the list into an ordered collection of consecutive sub-lists. E.g. split([1,2,3,4,5,3,6], 3) -> ([1,2],[4,5],[6]) , as opposed to dividing a list's elements by category. Discussion of the same topic on python-list.
Python String split() MethodThe split() method splits a string into a list. You can specify the separator, default separator is any whitespace.
The split() method of the string class is fairly straightforward. It splits the string, given a delimiter, and returns a list consisting of the elements split out from the string. By default, the delimiter is set to a whitespace - so if you omit the delimiter argument, your string will be split on each whitespace.
good, bad = [], [] for x in mylist: (bad, good)[x in goodvals].append(x)
good = [x for x in mylist if x in goodvals] bad = [x for x in mylist if x not in goodvals]
is there a more elegant way to do this?
That code is perfectly readable, and extremely clear!
# 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]
Again, this is fine!
There might be slight performance improvements using sets, but it's a trivial difference, and I find the list comprehension far easier to read, and you don't have to worry about the order being messed up, duplicates being removed as so on.
In fact, I may go another step "backward", and just use a simple for loop:
images, anims = [], [] for f in files: if f.lower() in IMAGE_TYPES: images.append(f) else: anims.append(f)
The a list-comprehension or using set()
is fine until you need to add some other check or another bit of logic - say you want to remove all 0-byte jpeg's, you just add something like..
if f[1] == 0: continue
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With