Python:从range(n)生成k个元组,仅按顺序包含元组

时间:2019-11-19 18:04:22

标签: python sorting tuples lexicographic

示例:给定k = 3和n = 3,很容易生成条目为0或1或2的所有三元组的列表。

  

[(0,0,0),(0,0,1),(0,0,2),(0,1,0),(0,1,1),(0,1,2 ),(0、2、0),(0、2、1),(0、2、2),(1、0、0),(1、0、1),(1、0、2), (1、1、0),(1、1、1),(1、1、2),(1、2、0),(1、2、1),(1、2、2),(2 ,0,0),(2,0,1),(2,0,2),(2,1,0),(2,1,1),(2,1,2),(2,2 ,0),(2,2,1),(2,2,2)]

但是,在我的上下文中,元组(0,1,2),(0,2,1),(1,2,0),(1,0,2),(2,0,1) ,(2,1,0)都是“相同的”(以不同的顺序排列相同的条目),因此我只想保留其中之一。在这六个中,(0,1,2)是条目为“按顺序”的那个,所以我只想保留那个。

同样,元组(0,1,1)(1,0,1),(1,1,0)都相同,所以我只想保留(0,1,1)。

目标:某些函数generate_my_tuples(n,k)会生成所有长度为k的元组的列表,其条目在range(n)内,但是仅是“按顺序”版本的如上所述,每个可能的元组

对于上面的示例,我希望输出为:

  

[(0,0,0),(0,0,1),(0,0,2),(0,1,1),(0,1,2),(0,2,2 ),(1,1,1),(1,1,2),(1,2,2),(2,2,2)]

作为一个额外的目标,如果该函数还创建了已删除的元组的列表,那将是很好的选择。

评论:我可以看到在k = 2时如何执行此操作,因此每个元组只有一个“正确”和一个“错误”顺序。但是,我看不到如何将其概括为任意k(其中,元组的“不正确”版本的数量甚至取决于元组中的条目)。就我而言,我真的需要这个函数来覆盖所有可能的n和k。

3 个答案:

答案 0 :(得分:6)

您可以使用itertools.combinations_with_replacement

  

从可迭代输入中返回元素的r长度子序列   允许单个元素重复多次。

     

组合按字典顺序排序。所以,如果输入   可迭代的被排序,组合元组将被排序   订购。       从itertools导入groups_with_replacement

k = 3
n = 3

list(combinations_with_replacement(range(n), k))

输出:

[(0, 0, 0),
 (0, 0, 1),
 (0, 0, 2),
 (0, 1, 1),
 (0, 1, 2),
 (0, 2, 2),
 (1, 1, 1),
 (1, 1, 2),
 (1, 2, 2),
 (2, 2, 2)]

如果还需要省略的元组,则可以使用product生成所有可能的输出,并删除有效的输出:

from itertools import combinations_with_replacement, product

k = 3
n = 3

valid = list(combinations_with_replacement(range(n), k))
omitted = set(product(range(n), repeat=k)) - set(valid)
print(omitted)

输出:

 {(0, 2, 0), (1, 2, 1), (1, 1, 0), (1, 2, 0), (2, 1, 0), (0, 1, 0), 
  (1, 0, 0), (2, 2, 1), (2, 0, 2), (2, 1, 1), (1, 0, 1), (2, 2, 0), 
  (2, 0, 1), (2, 1, 2), (0, 2, 1), (2, 0, 0), (1, 0, 2)}

编辑:

按照您在评论中的要求,可以将此输出转换为所需的格式(递归嵌套的元组),如下所示:

from itertools import combinations_with_replacement, product

def recursively_nested(t):
    if len(t) <= 2:
        return t
    else:
        return recursively_nested(t[:-1]), t[-1]


k = 4
n = 3

valid = list(combinations_with_replacement(range(n), k))
out = [recursively_nested(t) for t in valid]
print(out)
# [(((0, 0), 0), 0), (((0, 0), 0), 1), (((0, 0), 0), 2), (((0, 0), 1), 1), (((0, 0), 1), 2), ...]

答案 1 :(得分:2)

我建议您使用itertools.product和字典(用于存储删除的元组):

from itertools import product

n, k = 3, 3
data = list(product(range(n), repeat=k))

result = {}
for t in data:
    key = tuple(sorted(t))
    result.setdefault(key, []).append(t)

print(list(result.keys()))

输出

[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1), (0, 1, 2), (0, 2, 2), (1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)]

请注意,字典的值是已删除的元组,例如

for key, value in result.items():
    print(key, value)

输出

(0, 0, 0) [(0, 0, 0)]
(0, 0, 1) [(0, 0, 1), (0, 1, 0), (1, 0, 0)]
(0, 0, 2) [(0, 0, 2), (0, 2, 0), (2, 0, 0)]
(0, 1, 1) [(0, 1, 1), (1, 0, 1), (1, 1, 0)]
(0, 1, 2) [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
(0, 2, 2) [(0, 2, 2), (2, 0, 2), (2, 2, 0)]
(1, 1, 1) [(1, 1, 1)]
(1, 1, 2) [(1, 1, 2), (1, 2, 1), (2, 1, 1)]
(1, 2, 2) [(1, 2, 2), (2, 1, 2), (2, 2, 1)]
(2, 2, 2) [(2, 2, 2)]

答案 2 :(得分:0)

我将追求额外的目标,一个函数返回选定的列表,剩下的作为集合(而不是列表)。

from itertools import combinations_with_replacement, product

k=3 
n=3

def extra_goal(k, n):
    selected = list(combinations_with_replacement(range(n), k))
    removed = set(product(range(n), repeat=k)) - set(selected)
    return selected, removed

print(extra_goal(k, n))

输出:

([(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 1), (0, 1, 2), (0, 2, 2), (1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)], 
{(0, 2, 0), (1, 2, 1), (1, 1, 0), (1, 2, 0), (2, 1, 0), (0, 1, 0), (1, 0, 0), (2, 2, 1), (2, 0, 2), (2, 1, 1), (1, 0, 1), (2, 2, 0), (2, 0, 1), (2, 1, 2), (0, 2, 1), (2, 0, 0), (1, 0, 2)})