小能豆

如何根据子集长度条件迭代列表的所有分区

py

出于某些目的,我需要生成一个可迭代对象,列出列表的所有分区,但对子集的长度有一个条件。也就是说,我想将列表划分为相等长度的子集(此处 =3),但最后一个子集除外,如果列表的长度不是 3 的倍数。

即 [‘a’,’b’,’c’,’d’,’e’] 应为所有分区提供长度分别为 3 和 2 的 2 个子集。

也就是说,如果我简单使用:

[p for p in multiset_partitions(['a','b','c','d','e'],2)]
Out: 
[[['a', 'b', 'c', 'd'], ['e']],
[['a', 'b', 'c', 'e'], ['d']],
[['a', 'b', 'c'], ['d', 'e']],
         .....
[['a', 'd'], ['b', 'c', 'e']],
[['a', 'e'], ['b', 'c', 'd']],
[['a'], ['b', 'c', 'd', 'e']]]

我全都搞定了。所以到目前为止,我最好的尝试就是过滤掉包含至少一个长度 > 3 子集的分区:

from sympy.utilities.iterables import multiset_partitions    

def partitions(liste):
   compte = 0
   n = len(liste)//3 + 1
   for p in multiset_partitions(liste,n):
      l = len(p)
      oversize = False
      i = 0
      while not(oversize) and i != l:
         if len(p[i])>3:
            oversize=True
         i+=1

      if oversize == False:
         compte += 1

      #do something with p

   return(compte) #I'm just counting out the number of partitions right now

这确实有效,但显然不是实现我想要的最有效方法。尤其是当列表长度增加时,分区数量会很快变得非常大。

(长度为 5 时为 10,但长度为 10 时为 9100,长度为 13 时为 800800…)

最有效的 Python 方式应该是什么?


阅读 20

收藏
2025-01-06

共1个答案

小能豆

您始终可以绕过filter分区函数。您可以使用lambda函数来确保除最后一个元素外,所有元素的长度均为 3。

list(filter(lambda x: all(len(z)==3 for z in x[:-1]), multiset_partitions('abcde', 2)))
# returns:
[[['a', 'b', 'c'], ['d', 'e']],
 [['a', 'b', 'd'], ['c', 'e']],
 [['a', 'b', 'e'], ['c', 'd']],
 [['a', 'c', 'd'], ['b', 'e']],
 [['a', 'c', 'e'], ['b', 'd']],
 [['a', 'd', 'e'], ['b', 'c']]]

在选择分区数量时,您必须小心谨慎,以确保使用的是ceil。例如,对于 10 个项目,您ceil(10/3)不需要10//3

2025-01-06