什么是更加pythonic的方式基于长度生成新的列表列表?

时间:2013-04-09 22:43:19

标签: python

我有一个列表列表,对于列表中的每个列表,我想将它拆分为两个列表,这样每个列表的长度最多为30,否则我会丢弃不能容纳的列表。并且差不多接近30。

例如:列表1的长度为64 - >将它分成两个30,30的列表,并丢弃剩下的4个。

或List 2的长度为41,我生成一个新的30列表并丢弃11.

或列表3的长度为58,我生成两个30和28的列表。

我正在使用我找到的列表拆分功能:https://stackoverflow.com/a/1751478/2027556

现在我的代码是这样的:

new_list = []
for list_ in cluster:
    if len(list_) < 31 and len(list_) > 24:
       new_list.append(list_)
    elif len(list_) >= 31:
       chunks_list = chunks(list_, 30)
       for item in chunks_list:
          if len(item) > 25:
             new_list.append(item)

正如你现在所看到的那样我只是制作一个新列表并通过旧列表,但我认为有一个更优雅的pythonic解决方案可能使用列表理解?

8 个答案:

答案 0 :(得分:2)

不需要太聪明,你可以使用step参数range()

cluster = list(range(100))
chunk_size = 30
result = [cluster[start:start+chunk_size] 
          for start in range(0, len(cluster), chunk_size)]
# discard last chunk if too small - adjust the test as needed
if len(result[-1]) < chunk_size:
    del result[-1]

result的值将是列表列表:

[ [0, 1, ..., 29],
  [30, 31, ..., 59],
  [60, 61, ..., 89] ]

(那说你还没有真正描述输入和输出太清楚 - 即没有给出具体的例子。)

答案 1 :(得分:0)

以下内容应该有效:

tmp = ((x[i:i+30] for i in range(0, len(x), 30)) for x in cluster)
new_list = [x for lst in tmp for x in lst if len(x) > 25]

答案 2 :(得分:0)

new_list = [[lst[i*30:(i+1)*30] for i in xrange(len(lst)/30)] for lst in cluster]

答案 3 :(得分:0)

首先,我使用itertools docs中的grouper食谱来获取群组:

new_list = list(grouper(30, cluster))

然后过滤最后一组以删除fillvalue条目,如果结果不是“大约接近30”,则将其删除。

new_list[-1] = list(filter(None, new_list[-1]))
if len(new_list) < chunk_size:
    del result[-1]

如果None是有效元素,请使用其他内容作为哨兵:

sentinel = object()
new_list = list(grouper(30, cluster, fillvalue=sentinel)
new_list[-1] = [element for element in new_list[-1] if element is not sentinel]
if len(new_list[-1]) < chunk_size:
    del result[-1]

与此同时,有一些关于添加zip_strictitertools的讨论,这将允许grouper食谱返回一个简短的最终组,而不是用fillvalue填充它。如果这种情况发生在3.4中,你可以将其简化为:

new_list = list(grouper(30, cluster, strict=True))
if len(new_list[-1]) < chunk_size:
    del result[-1]

或者,当然,你可以使用python-ideas列表中的一个“严格的分组器”实现,或者只编写你自己的grouperfilter个调用上方。

答案 4 :(得分:0)

如果你真的想要列表理解......

new_list = [cluster[i:i+30] for i in xrange(0, len(cluster), 30) if len(cluster[i:i+30]) > 25]

答案 5 :(得分:0)

您可以使用生成器功能以及itertools.islice

In [11]: from itertools import islice

In [12]: lis=[range(64),range(41),range(58)]

In [13]: def solve(lis):
    for x in lis:
        it=iter(x)
        q,r=divmod(len(x),30)
        if r>25:
            for _ in xrange(q+1):
               yield list(islice(it,30)) 
        else:        
            for _ in xrange(q):
                yield list(islice(it,30))
   ....:                 

In [14]: map(len,list(solve(lis))) #use just `list(solve(lis))` to get the desired answer
Out[14]: [30, 30, 30, 30, 28] # (30,30) from 64, (30) from 41, and (30,28) from 58

答案 6 :(得分:0)

对于两个列表,只需编写2个切片

new_list = [cluster[:30], cluster[30:60]]

答案 7 :(得分:0)

从python itertools修改grouper,您可以执行以下操作:

def grouper(n, iterable, max_chunks):
    args = [iter(iterable)] * n
    chunks = []

    for zipped in zip_longest(fillvalue=None, *args):
        chunks.append([x for x in zipped if x is not None])
        if(len(chunks) == max_chunks):
            break

    return chunks

new_lists = [grouper(10,li,2) for li in list_list]

这将返回一个作为拆分列表的块列表 如果你想要这个更平坦,你可以这样称呼:

new_lists = []
for li in list_list:
    new_lists.extend(grouper(10,li,2))