Py学习  »  Python

如何在python中按n个元素分组元素,而无需列表切片?

Ahmad Khan • 2 年前 • 642 次点击  

Link to original question

>>> theList = list(range(10))
>>> N = 3
>>> subList = [theList[n:n+N] for n in range(0, len(theList), N)]
>>> subList
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

如果没有列表切片,我该怎么做?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/130724
 
642 次点击  
文章 [ 3 ]  |  最新文章 2 年前
Alain T.
Reply   •   1 楼
Alain T.    2 年前

有几种方法:

您可以使用嵌套列表理解,将索引放入列表中:

(不过,索引的广泛使用是非常不和谐的)

theList = list(range(10))
N       = 3
L       = len(theList)
subList = [ [theList[j] for j in range(i,min(i+N,L))] for i in range(0,L,N) ]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

你也可以用itertools来做。groupby使用迭代器作为分组键或itertools。每个子范围的islice(,N):

from itertools import groupby

group   = iter(range(len(theList)))
subList = [ list(g) for _,g in groupby(theList,key=lambda _:next(group)//N) ]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

from itertools import islice

iList   = iter(theList)
subList = [ list(islice(iList,N)) for _ in range(0,len(theList),N) ]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

如果不能使用库,可以使用zip()获取列表中的迭代器块:

iList   = iter(theList)
subList = [[n for _,n in zip(range(N),iList)] for _ in range(0,len(theList),N)]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

或者使用next()函数进行映射:

iList   = iter(theList)
subList = [ [f, *map(next,[iList]*(N-1))] for f in iList ]
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]] 

当然,总有好的for循环方法:

subList = [[]]
for n in theList:
    L,V = (subList[-1],n) if len(subList[-1])<N else (subList,[n]) 
    L.append(V)
print(subList)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
njp
Reply   •   2 楼
njp    2 年前

下面是一个使用itertools(可能是过度杀戮)的解决方案:

第一步。转换 theList 进入发电机:

gList = (x for x in theList)

第二步。 itertools.islice 产生N组(永远):

import itertools as it
z1 = list(it.islice(gList,N)) # [0,1,2]
z2 = list(it.islice(gList,N)) # [3,4,5]
z3 = list(it.islice(gList,N)) # [6,7,8]
z4 = list(it.islice(gList,N)) # [9]
z5 = list(it.islice(gList,N)) # [], etc.

(注意,我们需要重置 gList 在这之后。)

第三步。用另一台发电机将其包裹起来,然后使用 itertools.takewhile :

import itertools as it
gList = (x for x in theList)
subList = list(it.takewhile(lambda y: len(y) > 0, 
                            (list(it.islice(gList,N)) for _ in it.count(1))))

在这里 it.count(1) 表现得像个 while True:

mkrieger1 John Antonio Anselmo
Reply   •   3 楼
mkrieger1 John Antonio Anselmo    2 年前

使用模数运算符 % .

def split_by_n(n, lst):
  final = []
  sublist = []
  for i in range(0, len(lst)):
    if i % n != 0: # if i/n has no remainders
      sublist.append(lst[i])
    elif i != 0: # Reached the end of a sublist. Append to parent and reset.
      final.append(sublist)
      sublist = []
      sublist.append(lst[i])
    else: # 0 mod n is 0, so just make sure to add it anyways
      sublist.append(lst[i])
  final.append(sublist)
  return final