An elegant way to slice a list with a condition

Given the list [2,8,13,15,24,30], all of whose elements should be in the range (31). Now I want to cut it into 3 lists, the first list with numbers from 0 to 10, the second with numbers from 11 to 20, and the rest in the rest.

Here is my ugly code:

numbers = [2,8,13,15,24,30] mylist = [[],[],[]] # I hate this the most... for i in numbers: if i <= 10 : mylist[0].append(i) elif i > 10 and i <= 20: mylist[1].append(i) else: mylist[2].append(i) print mylist 

I don't think this is a good way to do this. Any suggestions please?

+5
source share
6 answers

Since your input is sorted, you can do it in one go with itertools.groupby :

 from itertools import groupby [list(g) for _,g in groupby(numbers, lambda x: x//10)] Out[3]: [[2, 8], [13, 15], [24, 26]] 

There is no need to initialize a bunch of lists in this way, groupby gives them on the fly.

This may be one after another in terms of how you wanted to handle modulo 10 boundaries; if unclear, you can always define your own grouper function:

 def grouper(x): '''bins matching the semantics: [0,10] (10,20] (20, 30]''' return (x-1)//10 if x > 0 else 0 

and use it like this:

 numbers = [2,8,13,15,24,30] [list(g) for _,g in groupby(numbers, grouper)] Out[5]: [[2, 8], [13, 15], [24, 30]] 
+3
source

Without rethinking your basic approach, you can:

 for n in numbers: mylist[n//10].append(n) 

This uses integer division, for example. 19//10 = 1.

There are much more elegant ways to do this using other Python constructs; I will make a second answer for them. But for now, this is a quick, easy, and not too sickening way to do what you want.

+1
source
 def filterList(original, lower, upper): return filter(lambda i : i > lower and i <= upper, original) 

It can be called that

 firstSlice = filterList(numbers, 0, 10) >>> firstSlice [2, 8] 

Creating a Range List

 ranges = [0, 10, 20, 30] 

Then, making a 2D list in list comprehension

 >>> [filterList(numbers, ranges[i], ranges[i+1]) for i in range(len(ranges)-1)] [[2, 8], [13, 15], [24, 26]] 
+1
source

How about using reduce ?

 numbers = [2,8,13,15,24,26] def part(acc, x): # first list with numbers from 0 to 10, # the second one with numbers from 11 to 20, # and the others into the rest. # # This is *not* the same as: # acc[x/10].append(x) # if x < 10: acc[0].append(x) elif x > 20: acc[2].append(x) else: acc[1].append(x) return acc print reduce(part, numbers, [[],[],[]]) 

And delete hated [[],[],[]] if you can live with a dictionary instead of a list:

 from collections import defaultdict numbers = [2,8,13,15,24,26] def part(acc, x): if x < 10: acc[0].append(x) elif x > 20: acc[2].append(x) else: acc[1].append(x) return acc print reduce(part, numbers, defaultdict(list)) 

Production:

 defaultdict(<type 'list'>, {0: [2, 8], 1: [13, 15], 2: [24, 26]}) 
+1
source

One of the best ways to do this uses defaults by default:

 from collections import defaultdict output = defaultdict(list) for n in numbers: output[n//10].append(n) 

This creates a dict with a default element (if you use a key that was not created), which is an empty list. You do not need to create empty lists of lists that you do not like in the source code.

Then you can access the output in a decade, i.e. as long as output is a dict, output[0] is a list.

If you need to keep the original output logic, converting this dict to a list of lists is simple.

+1
source

Not sure what matters for the elegant but enumerated concepts of shoudl work:

 numbers = [2,8,13,15,24,26] mylist = [] mylist.append([x for x in numbers if x <=10]) mylist.append([x for x in numbers if x > 10 and x <= 20]) mylist.append([x for x in numbers if x > 2 ]) print mylist 
0
source

Source: https://habr.com/ru/post/1200853/


All Articles