我想找到所有可能的方法将一系列(连续的)整数M = {0,1,2,...,m}映射到另一系列整数N = {0,1,2,... ,n}其中m> n,受制于约束,即M中只有连续的整数映射到N中的相同整数。
下面的python代码接近(start
对应于M中的第一个元素,stop
- 1对应于M中的最后一个元素,nbins
对应于| N |):
import itertools
def find_bins(start, stop, nbins):
if (nbins > 1):
return list(list(itertools.product([range(start, ii)], find_bins(ii, stop, nbins-1))) for ii in range(start+1, stop-nbins+2))
else:
return [range(start, stop)]
E.g
In [20]: find_bins(start=0, stop=5, nbins=3)
Out[20]:
[[([0], [([1], [2, 3, 4])]),
([0], [([1, 2], [3, 4])]),
([0], [([1, 2, 3], [4])])],
[([0, 1], [([2], [3, 4])]),
([0, 1], [([2, 3], [4])])],
[([0, 1, 2], [([3], [4])])]]
但是,正如你可以看到输出是嵌套的,并且在我的生命中,我无法找到一种方法来正确修改代码而不会破坏它。
所需的输出如下所示:
In [20]: find_bins(start=0, stop=5, nbins=3)
Out[20]:
[[(0), (1), (2, 3, 4)],
[(0), (1, 2), (3, 4)],
[(0), (1, 2, 3), (4)],
[(0, 1), (2), (3, 4)],
[(0, 1), (2, 3), (4)],
[(0, 1, 2), (3), (4)]]
答案 0 :(得分:1)
我建议采用不同的方法:分区为n
非空箱由n-1
个不同的索引唯一确定,这些索引标记箱之间的边界,第一个标记位于第一个元素之后,和最后一个元素之前的最终标记。 itertools.combinations()
可以直接用于生成所有这样的索引元组,然后只需将它们用作切片索引即可。像这样:
def find_nbins(start, stop, nbins):
from itertools import combinations
base = range(start, stop)
nbase = len(base)
for ixs in combinations(range(1, stop - start), nbins - 1):
yield [tuple(base[lo: hi])
for lo, hi in zip((0,) + ixs, ixs + (nbase,))]
然后,例如,
for x in find_nbins(0, 5, 3):
print(x)
显示:
[(0,), (1,), (2, 3, 4)]
[(0,), (1, 2), (3, 4)]
[(0,), (1, 2, 3), (4,)]
[(0, 1), (2,), (3, 4)]
[(0, 1), (2, 3), (4,)]
[(0, 1, 2), (3,), (4,)]
只是注意到这里存在一个更普遍的潜在问题:生成将任意序列分解为n
非空箱的方法。然后,这里的具体问题是将其应用于序列range(start, stop)
。我相信以这种方式查看它会使代码更容易理解,所以这里是:
def gbins(seq, nbins):
from itertools import combinations
base = tuple(seq)
nbase = len(base)
for ixs in combinations(range(1, nbase), nbins - 1):
yield [base[lo: hi]
for lo, hi in zip((0,) + ixs, ixs + (nbase,))]
def find_nbins(start, stop, nbins):
return gbins(range(start, stop), nbins)
答案 1 :(得分:0)
这就是我想要的;我很乐意接受更简单,更优雅的解决方案:
def _split(start, stop, nbins):
if (nbins > 1):
out = []
for ii in range(start+1, stop-nbins+2):
iterator = itertools.product([range(start, ii)], _split(ii, stop, nbins-1))
for item in iterator:
out.append(item)
return out
else:
return [range(start, stop)]
def _unpack(nested):
unpacked = []
if isinstance(nested, (list, tuple)):
for item in nested:
if isinstance(item, tuple):
for subitem in item:
unpacked.extend(_unpack(subitem))
elif isinstance(item, list):
unpacked.append([_unpack(subitem) for subitem in item])
elif isinstance(item, int):
unpacked.append([item])
return unpacked
else: # integer
return nested
def find_nbins(start, stop, nbins):
nested = _split(start, stop, nbins)
unpacked = [_unpack(item) for item in nested]
return unpacked