1

我有一个列表列表,对于列表中的每个列表,我想将其拆分为两个列表,以便每个列表的长度最大为 30,否则我会丢弃无法放入 30 且不包含的剩余部分t 大约接近 30。

例如:列表 1 的长度为 64 -> 将其拆分为 30、30 的两个列表,并丢弃剩余的 4 个。

或列表 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 解决方案可能使用列表理解?

4

8 回答 8

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

(也就是说你还没有真正描述过输入和输出的内容——即没有给出具体的例子。)

于 2013-04-09T22:51:13.837 回答
0

首先,我会使用文档grouper中的配方来获取组:itertools

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_strictto的讨论itertools,这将允许grouper返回一个简短的最终组的配方,而不是用fillvalue. 如果这发生在 3.4 中,您可以将其简化为:

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

或者,当然,您可以使用 python-ideas 列表中的“严格分组器”实现之一,或者只是编写自己的来包装上面的grouperandfilter调用。

于 2013-04-09T22:53:57.320 回答
0

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

new_list = [cluster[i:i+30] for i in xrange(0, len(cluster), 30) if len(cluster[i:i+30]) > 25]
于 2013-04-09T22:55:36.013 回答
0

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

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))
于 2013-04-09T23:16:36.853 回答
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]
于 2013-04-09T22:51:24.253 回答
0

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

于 2013-04-09T22:52:00.110 回答
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
于 2013-04-09T22:57:29.787 回答
0

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

new_list = [cluster[:30], cluster[30:60]]
于 2013-04-09T23:03:23.560 回答