将列表拆分为长度大致相等的 N 个部分
将列表分成大致相等部分的最佳方法是什么?例如,如果列表有 7 个元素,并将其分为 2 部分,我们希望在一部分中获取 3 个元素,而另一部分应该有 4 个元素。
我正在寻找类似 even_split(L, n)
的东西,它将 L
分成 n
部分。
def chunks(L, n):
""" Yield successive n-sized chunks from L.
"""
for i in range(0, len(L), n):
yield L[i:i+n]
上面的代码给出了 3 个块,而不是 3 个块。我可以简单地转置(迭代它并获取每列的第一个元素,将该元素称为第一部分,然后获取第二个元素并将其放入第二部分,等等),但这会破坏项目的顺序。
What is the best way to divide a list into roughly equal parts? For example, if the list has 7 elements and is split it into 2 parts, we want to get 3 elements in one part, and the other should have 4 elements.
I'm looking for something like even_split(L, n)
that breaks L
into n
parts.
def chunks(L, n):
""" Yield successive n-sized chunks from L.
"""
for i in range(0, len(L), n):
yield L[i:i+n]
The code above gives chunks of 3, rather than 3 chunks. I could simply transpose (iterate over this and take the first element of each column, call that part one, then take the second and put it in part two, etc), but that destroys the ordering of the items.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
您可以相当简单地将其编写为列表生成器:
示例:
You can write it fairly simply as a list generator:
Example:
这是 存在的理由
numpy.array_split
*:*归功于零比雷埃夫斯 在 6 号房间
This is the raison d'être for
numpy.array_split
*:*credit to Zero Piraeus in room 6
只要你不想要任何像连续块这样的愚蠢的东西:
As long as you don't want anything silly like continuous chunks:
此代码由于舍入错误而损坏。不要使用它!!!
这是一个可行的方法:
测试:
This code is broken due to rounding errors. Do not use it!!!
Here's one that could work:
Testing:
如果将
n
元素划分为大约k
块,则可以使n % k
块比其他块大 1 个元素,以分配额外的元素。以下代码将为您提供块的长度:
示例:
n=11, k=3
结果为[4, 4, 3]
然后,您可以轻松计算块的起始索引:
示例:
n=11, k=3
结果为[0, 4, 8]
使用第
i+1
个块作为边界,我们得到列表l
的第i
块,其中 lenn< /code>
最后一步是使用列表理解从所有块中创建一个列表:
示例:
n=11, k=3, l=range(n)
结果为[范围(0, 4), 范围(4, 8), 范围(8, 11)]
If you divide
n
elements into roughlyk
chunks you can maken % k
chunks 1 element bigger than the other chunks to distribute the extra elements.The following code will give you the length for the chunks:
Example:
n=11, k=3
results in[4, 4, 3]
You can then easily calculate the start indizes for the chunks:
Example:
n=11, k=3
results in[0, 4, 8]
Using the
i+1
th chunk as the boundary we get that thei
th chunk of listl
with lenn
isAs a final step create a list from all the chunks using list comprehension:
Example:
n=11, k=3, l=range(n)
results in[range(0, 4), range(4, 8), range(8, 11)]
更改代码以生成
n
块而不是n
块:这会给出:
这会将额外的元素分配给最终组,该组并不完美,但完全符合您的规范“大约 N 个相等的部分”:-) 我的意思是 56 个元素会比 (19,19,18) 更好,而这给出 (18,18,20)。
您可以使用以下代码获得更平衡的输出:
输出:
Changing the code to yield
n
chunks rather than chunks ofn
:which gives:
This will assign the extra elements to the final group which is not perfect but well within your specification of "roughly N equal parts" :-) By that, I mean 56 elements would be better as (19,19,18) whereas this gives (18,18,20).
You can get the more balanced output with the following code:
which outputs:
这将通过一个表达式分割成相等的部分,同时保持顺序:
这些部分的差异不超过一个元素。将 18 分成 5 部分,得到 3 + 4 + 3 + 4 + 4 = 18。
This will do the split into equal parts by one single expression while keeping the order:
The parts will differ in not more than one element. The split of 18 into 5 parts results in 3 + 4 + 3 + 4 + 4 = 18.
请参阅
more_itertools.divide
:通过
> 安装pip install more_itertools
。See
more_itertools.divide
:Install via
> pip install more_itertools
.使用列表理解:
Using list comprehension:
这是添加
None
以使列表长度相等的列表Here is one that adds
None
to make the lists equal length看看 numpy.split:
Have a look at numpy.split:
这是一个可以处理任何正数(整数)块的生成器。如果块的数量大于输入列表长度,则某些块将为空。该算法在短块和长块之间交替而不是分离它们。
我还包含了一些用于测试
ragged_chunks
函数的代码。我们可以通过将乘法导出到
range
调用中来稍微提高效率,但我认为以前的版本更具可读性(并且更干燥)。Here's a generator that can handle any positive (integer) number of chunks. If the number of chunks is greater than the input list length some chunks will be empty. This algorithm alternates between short and long chunks rather than segregating them.
I've also included some code for testing the
ragged_chunks
function.We can make this slightly more efficient by exporting the multiplication into the
range
call, but I think the previous version is more readable (and DRYer).假设您想要将列表 [1, 2, 3, 4, 5, 6, 7, 8] 拆分为 3 个元素列表,
例如 [[1,2,3], [ 4, 5, 6], [7, 8]],如果最后剩下的元素小于3,则将它们分组在一起。
输出: [[1,2,3], [4, 5, 6], [7, 8]]
其中一个部分的长度为 3。将 3 替换为你自己的块大小。
Let's say you want to split a list [1, 2, 3, 4, 5, 6, 7, 8] into 3 element lists
like [[1,2,3], [4, 5, 6], [7, 8]], where if the last remaining elements left are less than 3, they are grouped together.
Output: [[1,2,3], [4, 5, 6], [7, 8]]
Where length of one part is 3. Replace 3 with your own chunk size.
这是我的解决方案:
产生
Here is my solution:
Produces
其他解决方案似乎有点长。这是使用列表理解和 NumPy 函数
array_split
的单行代码。 array_split(list, n) 会将list
简单地拆分为n
部分。The other solutions seem to be a bit long. Here is a one-liner using list comprehension and the NumPy function
array_split
.array_split(list, n)
will simply split thelist
inton
parts.使用 numpy.linspace 方法实现。
只需指定要将数组划分为多少部分即可。划分的大小将几乎相等。
例子 :
给出:
Implementation using numpy.linspace method.
Just specify the number of parts you want the array to be divided in to.The divisions will be of nearly equal size.
Example :
Gives :
我的解决方案,易于理解
,也是本页最短的一句话(由我的女孩写的)
My solution, easy to understand
And shortest one-liner on this page(written by my girl)
另一种方法是这样的,这里的想法是使用石斑鱼,但去掉
None
。在这种情况下,我们将拥有由列表第一部分的元素组成的所有“small_parts”,以及由列表后面部分的元素组成的“larger_parts”。 “较大部分”的长度为 len(small_parts) + 1。我们需要将 x 视为两个不同的子部分。我设置它的方式返回一个元组列表:
Another way would be something like this, the idea here is to use grouper, but get rid of
None
. In this case we'll have all 'small_parts' formed from elements at the first part of the list, and 'larger_parts' from the later part of the list. Length of 'larger parts' is len(small_parts) + 1. We need to consider x as two different sub-parts.The way I have it set up returns a list of tuples:
这是另一种变体,它将“剩余”元素均匀地分布在所有块中,一次一个,直到没有剩余的。在此实现中,较大的块出现在过程的开始处。
例如,从 14 个元素的列表中生成 4 个块:
Here's another variant that spreads the "remaining" elements evenly among all the chunks, one at a time until there are none left. In this implementation, the larger chunks occur at the beginning the process.
For example, generate 4 chunks from a list of 14 elements:
与 job's 答案相同,但考虑了大小小于块数的列表。
如果 n(块数)为 7 并且 lst(要划分的列表)为 [1, 2, 3],则块为 [[0], [1], [2]] 而不是 [[0], [1 ]、[2]、[]、[]、[]、[]]
The same as job's answer, but takes into account lists with size smaller than the number of chuncks.
if n (number of chunks) is 7 and lst (the list to divide) is [1, 2, 3] the chunks are [[0], [1], [2]] instead of [[0], [1], [2], [], [], [], []]
您还可以使用:
You could also use:
从此链接挑选,这对我有帮助。我有一个预先定义的清单。
Picked from this link, and this was what helped me. I had a pre-defined list.
示例:
l = [a for a in range(97)]
应由 10 个部分组成,除了最后一个之外,每个部分都有 9 个元素。输出:
Example:
l = [a for a in range(97)]
should be consist of 10 parts, each have 9 elements except the last one.Output:
1>
2>
1>
2>
这是处理大多数各种拆分情况的单个函数:
Here's a single function that handles most of the various split cases:
与作为生成器编写的 numpy.array_split 相同的行为,并且可以快速理解:
The same behavior like
numpy.array_split
written as a generator, and fast to understand:对 linspace 进行四舍五入并将其用作索引是比 amit12690 提出的更简单的解决方案。
Rounding the linspace and using it as an index is an easier solution than what amit12690 proposes.
我自己在这种情况下编写了代码:
divide_ports(1, 10, 9) 将返回
I've written code in this case myself:
divide_ports(1, 10, 9) would return
此代码适用于我(Python3 兼容):
示例(对于 bytearray 类型,但它也适用于 list ):
this code works for me (Python3-compatible):
example (for bytearray type, but it works for lists as well):