用条件切片列表的优雅方法

时间:2014-08-21 16:02:21

标签: python list

给出一个列表[2,8,13,15,24,30],其中所有元素都应该在范围内(31)。现在我想把它分成3个列表,第一个列表的数字从0到10,第二个列表的数字从11到20,其他的到其余的。

这是我丑陋的代码:

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

我认为这不是一个很好的方法。有什么建议吗?

6 个答案:

答案 0 :(得分:3)

由于您的输入已排序,您可以使用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]]

无需以这种方式初始化一堆列表,groupby可以即时生成它们。

就你想要如何处理模10边界而言,这可能是一个接一个的;如果不清楚你总是可以定义自己的grouper函数:

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

并因此使用它:

numbers = [2,8,13,15,24,30]

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

答案 1 :(得分:1)

如果不重新考虑您的基本方法,您可以:

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

这利用整数除法,例如19//10 = 1。

使用其他Python构造有更多优雅的方法可以做到这一点;我会为那些人做出第二个答案。但是现在,这是一种快速,简单且不太令人作呕的方式来做你想做的事。

答案 2 :(得分:1)

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

这可以像这样调用

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

制作你的范围列表

ranges = [0, 10, 20, 30]

然后在列表理解中制作2D列表

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

答案 3 :(得分:1)

如何使用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, [[],[],[]])

要删除讨厌的[[],[],[]],如果你可以使用字典而不是列表:

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))

产:

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

答案 4 :(得分:1)

一种更好的方法是使用默认的dicts:

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

这会创建一个带有默认元素的dict(如果访问尚未创建的键),则为空列表。您不需要在原始代码示例中创建您不喜欢的空列表列表。

然后您可以按十年访问输出,即output是dict时,output[0]是一个列表。

如果您需要保留原始输出逻辑,将此dict转换为列表列表很简单。

答案 5 :(得分:0)

不确定优雅的重要性,但列表推导应该有效:

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