Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split a list based on a condition?

Tags:

python

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] 
like image 403
Parand Avatar asked Jun 04 '09 07:06

Parand


People also ask

How do you split lists by condition?

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.

Can you use the split function with a list?

Python String split() MethodThe split() method splits a string into a list. You can specify the separator, default separator is any whitespace.

How do you split data in a list?

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.


2 Answers

good, bad = [], [] for x in mylist:     (bad, good)[x in goodvals].append(x) 
like image 168
John La Rooy Avatar answered Oct 17 '22 01:10

John La Rooy


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 
like image 36
dbr Avatar answered Oct 17 '22 00:10

dbr