以对数方式拆分 Python 列表
Split a Python list logarithmically
我正在尝试执行以下操作..
我有一个包含 n 个元素的列表。我想将这个列表分成 32 个单独的列表,随着我们接近原始列表的末尾,这些列表包含越来越多的元素。例如来自:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
我想得到这样的东西:
b = [[1],[2,3],[4,5,6,7],[8,9,10,11,12]]
我已经为包含 1024 个元素的列表完成了以下操作:
for i in range (0, 32):
c = a[i**2:(i+1)**2]
b.append(c)
但我正在愚蠢地努力寻找一种可靠的方法来为其他数字(如 256、512、2048)或其他数字列表而不是 32 执行此操作。
像这样应该可以解决问题。
for i in range (0, int(np.sqrt(2*len(a)))):
c = a[i**2:min( (i+1)**2, len(a) )]
b.append(c)
不是很 pythonic 但做你想做的事。
def splitList(a, n, inc):
"""
a list to split
n number of sublist
inc ideal difference between the number of elements in two successive sublists
"""
zr = len(a) # remaining number of elements to split into sublists
st = 0 # starting index in the full list of the next sublist
nr = n # remaining number of sublist to construct
nc = 1 # number of elements in the next sublist
#
b=[]
while (zr/nr >= nc and nr>1):
b.append( a[st:st+nc] )
st, zr, nr, nc = st+nc, zr-nc, nr-1, nc+inc
#
nc = int(zr/nr)
for i in range(nr-1):
b.append( a[st:st+nc] )
st = st+nc
#
b.append( a[st:max(st+nc,len(a))] )
return b
# Example of call
# b = splitList(a, 32, 2)
# to split a into 32 sublist, where each list ideally has 2 more element
# than the previous
总是这样。
>>> def log_list(l):
if len(l) == 0:
return [] #If the list is empty, return an empty list
new_l = [] #Initialise new list
new_l.append([l[0]]) #Add first iteration to new list inside of an array
for i in l[1:]: #For each other iteration,
if len(new_l) == len(new_l[-1]):
new_l.append([i]) #Create new array if previous is full
else:
new_l[-1].append(i) #If previous not full, add to it
return new_l
>>> log_list([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
[[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]
使用 iterator
,for
循环与 enumerate
和 itertools.islice
:
import itertools
def logsplit(lst):
iterator = iter(lst)
for n, e in enumerate(iterator):
yield itertools.chain([e], itertools.islice(iterator, n))
适用于任意数量的元素。示例:
for r in logsplit(range(50)):
print(list(r))
输出:
[0]
[1, 2]
[3, 4, 5]
[6, 7, 8, 9]
... some more ...
[36, 37, 38, 39, 40, 41, 42, 43, 44]
[45, 46, 47, 48, 49]
事实上,这与 this problem 非常相似,只是它使用 enumerate
来获取可变块大小。
这非常混乱,但可以完成工作。请注意,如果您对数 对列表进行切片,您将在开始时得到一些空箱。你的例子给出了算术索引序列。
from math import log, exp
def split_list(_list, divs):
n = float(len(_list))
log_n = log(n)
indices = [0] + [int(exp(log_n*i/divs)) for i in range(divs)]
unfiltered = [_list[indices[i]:indices[i+1]] for i in range(divs)] + [_list[indices[i+1]:]]
filtered = [sublist for sublist in unfiltered if sublist]
return [[] for _ in range(divs- len(filtered))] + filtered
print split_list(range(1024), 32)
编辑: 查看评论后,这里有一个可能适合您的示例:
def split_list(_list):
copy, output = _list[:], []
length = 1
while copy:
output.append([])
for _ in range(length):
if len(copy) > 0:
output[-1].append(copy.pop(0))
length *= 2
return output
print split_list(range(15))
# [[0], [1, 2], [3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14]]
请注意,此代码效率不高,但可以用作编写更好算法的模板。
我正在尝试执行以下操作..
我有一个包含 n 个元素的列表。我想将这个列表分成 32 个单独的列表,随着我们接近原始列表的末尾,这些列表包含越来越多的元素。例如来自:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
我想得到这样的东西:
b = [[1],[2,3],[4,5,6,7],[8,9,10,11,12]]
我已经为包含 1024 个元素的列表完成了以下操作:
for i in range (0, 32):
c = a[i**2:(i+1)**2]
b.append(c)
但我正在愚蠢地努力寻找一种可靠的方法来为其他数字(如 256、512、2048)或其他数字列表而不是 32 执行此操作。
像这样应该可以解决问题。
for i in range (0, int(np.sqrt(2*len(a)))):
c = a[i**2:min( (i+1)**2, len(a) )]
b.append(c)
不是很 pythonic 但做你想做的事。
def splitList(a, n, inc):
"""
a list to split
n number of sublist
inc ideal difference between the number of elements in two successive sublists
"""
zr = len(a) # remaining number of elements to split into sublists
st = 0 # starting index in the full list of the next sublist
nr = n # remaining number of sublist to construct
nc = 1 # number of elements in the next sublist
#
b=[]
while (zr/nr >= nc and nr>1):
b.append( a[st:st+nc] )
st, zr, nr, nc = st+nc, zr-nc, nr-1, nc+inc
#
nc = int(zr/nr)
for i in range(nr-1):
b.append( a[st:st+nc] )
st = st+nc
#
b.append( a[st:max(st+nc,len(a))] )
return b
# Example of call
# b = splitList(a, 32, 2)
# to split a into 32 sublist, where each list ideally has 2 more element
# than the previous
总是这样。
>>> def log_list(l):
if len(l) == 0:
return [] #If the list is empty, return an empty list
new_l = [] #Initialise new list
new_l.append([l[0]]) #Add first iteration to new list inside of an array
for i in l[1:]: #For each other iteration,
if len(new_l) == len(new_l[-1]):
new_l.append([i]) #Create new array if previous is full
else:
new_l[-1].append(i) #If previous not full, add to it
return new_l
>>> log_list([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
[[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]
使用 iterator
,for
循环与 enumerate
和 itertools.islice
:
import itertools
def logsplit(lst):
iterator = iter(lst)
for n, e in enumerate(iterator):
yield itertools.chain([e], itertools.islice(iterator, n))
适用于任意数量的元素。示例:
for r in logsplit(range(50)):
print(list(r))
输出:
[0]
[1, 2]
[3, 4, 5]
[6, 7, 8, 9]
... some more ...
[36, 37, 38, 39, 40, 41, 42, 43, 44]
[45, 46, 47, 48, 49]
事实上,这与 this problem 非常相似,只是它使用 enumerate
来获取可变块大小。
这非常混乱,但可以完成工作。请注意,如果您对数 对列表进行切片,您将在开始时得到一些空箱。你的例子给出了算术索引序列。
from math import log, exp
def split_list(_list, divs):
n = float(len(_list))
log_n = log(n)
indices = [0] + [int(exp(log_n*i/divs)) for i in range(divs)]
unfiltered = [_list[indices[i]:indices[i+1]] for i in range(divs)] + [_list[indices[i+1]:]]
filtered = [sublist for sublist in unfiltered if sublist]
return [[] for _ in range(divs- len(filtered))] + filtered
print split_list(range(1024), 32)
编辑: 查看评论后,这里有一个可能适合您的示例:
def split_list(_list):
copy, output = _list[:], []
length = 1
while copy:
output.append([])
for _ in range(length):
if len(copy) > 0:
output[-1].append(copy.pop(0))
length *= 2
return output
print split_list(range(15))
# [[0], [1, 2], [3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14]]
请注意,此代码效率不高,但可以用作编写更好算法的模板。