有没有一种方法可以生成项目列表的所有唯一排列

时间:2019-05-23 23:56:41

标签: python permutation itertools zebra-puzzle

我有五个属性的列表,每个属性都有五个不同的值。我想生成它们的笛卡尔积,并过滤所有唯一的排列。

一些背景:

我需要将它们用作解决逻辑难题的输入值。我在哪里检查规则以找到正确的解决方案。

from itertools import product

# input
names = ['Dana', 'Ingo', 'Jessica', 'Sören', 'Valerie']
ages = [26, 27, 30, 33, 35]
tops = ['Blouse', 'Poloshirt', 'Pullover', 'Sweatshirt', 'T-Shirt']
colors = ['blue', 'yellow', 'green', 'red', 'black']
sizes = ['XS', 'S', 'M', 'L', 'XL']

all_attributes = [names, ages, tops, colors, sizes]

# cartesian product (superset)
inputs = list(product(*all_attributes))

# the following code you do that...

也许一个简化的例子可以使之清楚。

数据:

[['Dana', 'Ingo'], [26, 27]]

笛卡尔数据积:

[('Dana', 26), ('Dana', 27), ('Ingo', 26), ('Ingo', 27)]

我想要什么:

[[('Dana', 26), ('Ingo', 27)],
 [('Dana', 27), ('Ingo', 26)],
 [('Ingo', 26), ('Dana', 27)],
 [('Ingo', 27), ('Dana', 26)]]

我不想要的东西:

[[('Dana', 26), ('Ingo', 26)], ...

我不希望多次出现相同的值。位置很重要,因此它应该具有置换性,并且对于具有五个元素的列表也应具有置换性。我猜输出的大小会很大,也许无法计算,所以最好指定一些固定的位置值。例如,我想将“ Dana”设置为第一个Element名称。

输出:

[[('Dana', 26), ('Ingo', 27),
 [('Dana', 27), ('Ingo', 26)]]

也许出于好奇,您可以告诉我这些概念的具体数学名称是什么,我需要什么?


实际难题:

五个朋友(Dana,Ingo,Jessica,Sören和Valerie)在购物中心的收银台排队等候。他们都是不同年龄段的人(26、27、30、33、35),并且想要购买不同的上衣(衬衫,马球衫,套头衫,运动衫,T恤)为自己。顶部的颜色为(蓝色,黄色,绿色,红色,黑色),尺寸为(XS,S,M,L,XL)

规则:

  1. 想要购买的顶级“达娜”是“ XL”。在她的背后(但不是紧随其后)是顶着“黑色”衣服的人。
  2. 'Jessica'直接在想要购买'Poloshirt'的人面前等候。
  3. 排队的第二个人想要购买“黄色”上衣。
  4. “ T恤”不是“红色”。
  5. 'Sören'想购买一件'运动衫'。直接在他前面等待的人比在他后面等待的人大。
  6. “ Ingo”需要尺寸为“ L”的顶部。
  7. 最后一位是30岁。
  8. 年龄最大的人将购买尺寸最小的上衣。
  9. 直接在“ Valerie”后面等候的人想购买比“ S”大的“红色”上衣。
  10. 最年轻的人想要购买“黄色”上衣。
  11. 杰西卡(Jessica)要买一件“衬衫”。
  12. 第三个排队等候的人想购买尺寸为M的上衣。
  13. “ Poloshirt”是“红色”或“黄色”或“绿色”。

2 个答案:

答案 0 :(得分:2)

这可以做到,但是需要很长时间。我缩小了列表的大小,因为您要求的选项具有24,883,200,000个排列:

from itertools import permutations, product

names = ['Dana', 'Ingo']
ages = [26, 27]
tops = ['Hemd', 'Poloshirt']
colors = ['blau', 'gelb']
sizes = ['XS', 'S']

options = []

# Generate the Cartesian product of all permutations of the options.
for name,age,top,color,size in product(*map(permutations,[names,ages,tops,colors,sizes])):
    # Build the option list. zip() transposes the individual lists.
    option = list(zip(name,age,top,color,size))
    options.append(option)
    print(option)

输出:

[('Dana', 26, 'Hemd', 'blau', 'XS'), ('Ingo', 27, 'Poloshirt', 'gelb', 'S')]
[('Dana', 26, 'Hemd', 'blau', 'S'), ('Ingo', 27, 'Poloshirt', 'gelb', 'XS')]
[('Dana', 26, 'Hemd', 'gelb', 'XS'), ('Ingo', 27, 'Poloshirt', 'blau', 'S')]
[('Dana', 26, 'Hemd', 'gelb', 'S'), ('Ingo', 27, 'Poloshirt', 'blau', 'XS')]
[('Dana', 26, 'Poloshirt', 'blau', 'XS'), ('Ingo', 27, 'Hemd', 'gelb', 'S')]
[('Dana', 26, 'Poloshirt', 'blau', 'S'), ('Ingo', 27, 'Hemd', 'gelb', 'XS')]
[('Dana', 26, 'Poloshirt', 'gelb', 'XS'), ('Ingo', 27, 'Hemd', 'blau', 'S')]
[('Dana', 26, 'Poloshirt', 'gelb', 'S'), ('Ingo', 27, 'Hemd', 'blau', 'XS')]
[('Dana', 27, 'Hemd', 'blau', 'XS'), ('Ingo', 26, 'Poloshirt', 'gelb', 'S')]
[('Dana', 27, 'Hemd', 'blau', 'S'), ('Ingo', 26, 'Poloshirt', 'gelb', 'XS')]
[('Dana', 27, 'Hemd', 'gelb', 'XS'), ('Ingo', 26, 'Poloshirt', 'blau', 'S')]
[('Dana', 27, 'Hemd', 'gelb', 'S'), ('Ingo', 26, 'Poloshirt', 'blau', 'XS')]
[('Dana', 27, 'Poloshirt', 'blau', 'XS'), ('Ingo', 26, 'Hemd', 'gelb', 'S')]
[('Dana', 27, 'Poloshirt', 'blau', 'S'), ('Ingo', 26, 'Hemd', 'gelb', 'XS')]
[('Dana', 27, 'Poloshirt', 'gelb', 'XS'), ('Ingo', 26, 'Hemd', 'blau', 'S')]
[('Dana', 27, 'Poloshirt', 'gelb', 'S'), ('Ingo', 26, 'Hemd', 'blau', 'XS')]
[('Ingo', 26, 'Hemd', 'blau', 'XS'), ('Dana', 27, 'Poloshirt', 'gelb', 'S')]
[('Ingo', 26, 'Hemd', 'blau', 'S'), ('Dana', 27, 'Poloshirt', 'gelb', 'XS')]
[('Ingo', 26, 'Hemd', 'gelb', 'XS'), ('Dana', 27, 'Poloshirt', 'blau', 'S')]
[('Ingo', 26, 'Hemd', 'gelb', 'S'), ('Dana', 27, 'Poloshirt', 'blau', 'XS')]
[('Ingo', 26, 'Poloshirt', 'blau', 'XS'), ('Dana', 27, 'Hemd', 'gelb', 'S')]
[('Ingo', 26, 'Poloshirt', 'blau', 'S'), ('Dana', 27, 'Hemd', 'gelb', 'XS')]
[('Ingo', 26, 'Poloshirt', 'gelb', 'XS'), ('Dana', 27, 'Hemd', 'blau', 'S')]
[('Ingo', 26, 'Poloshirt', 'gelb', 'S'), ('Dana', 27, 'Hemd', 'blau', 'XS')]
[('Ingo', 27, 'Hemd', 'blau', 'XS'), ('Dana', 26, 'Poloshirt', 'gelb', 'S')]
[('Ingo', 27, 'Hemd', 'blau', 'S'), ('Dana', 26, 'Poloshirt', 'gelb', 'XS')]
[('Ingo', 27, 'Hemd', 'gelb', 'XS'), ('Dana', 26, 'Poloshirt', 'blau', 'S')]
[('Ingo', 27, 'Hemd', 'gelb', 'S'), ('Dana', 26, 'Poloshirt', 'blau', 'XS')]
[('Ingo', 27, 'Poloshirt', 'blau', 'XS'), ('Dana', 26, 'Hemd', 'gelb', 'S')]
[('Ingo', 27, 'Poloshirt', 'blau', 'S'), ('Dana', 26, 'Hemd', 'gelb', 'XS')]
[('Ingo', 27, 'Poloshirt', 'gelb', 'XS'), ('Dana', 26, 'Hemd', 'blau', 'S')]
[('Ingo', 27, 'Poloshirt', 'gelb', 'S'), ('Dana', 26, 'Hemd', 'blau', 'XS')]

答案 1 :(得分:1)

将排列用于您所具有的逻辑难题类型的方法存在一个基本问题。问题甚至没有太多,以至于您的求解器不太可能在合理的时间内完成。问题是您没有一种自动的方法来检查规则以解决问题:除非您有一种方法来验证所有可能性,否则摆在您面前的一切可能性都是没有意义的。

为了解决这些问题,我创建了一个名为Puzzle Solvers的项目:

这是一个小型项目,当前仅包含一个感兴趣的类别:puzzle_solvers.elimination.Solver。此类实现了解决问题中提出的消除过程类型问题所需的大多数操作。所有逻辑都是documented,而tutorial是您确切问题的演练。我将在这里解释基础知识,以便您了解我所做的事情,甚至可以改善它。

第1步是要认识到队列中的位置是属性,就像年龄,姓名等一样。这意味着顺序不再相关。

步骤2是要认识到这是变相的图形问题。您有30个节点:五个个体中每个个体的所有可能属性(其中六个)。该图开始几乎完成。仅缺少给定类型的属性之间的边,因此从375开始,而不是从整个435开始。

最终目标是在图中的五个连接组件之间的每个属性类别之间具有一条边。因此,最终的边数为5 * 15 = 75。

那么如何去除边缘?诸如“'T恤'不是'红色'”之类的简单规则非常简单:只需删除该边缘即可。例如“队列中的最后一个人是30岁”之类的规则。也很简单,并且在去除边缘方面更有利可图。年龄在30岁与5岁之间的所有边缘以及所有不在5岁与30岁之间的边缘都被删除。我添加了两个半熟的实用包装,以检查大于和小于条件删除代表不可能组合的边缘。

求解器最重要的方面是这样的事实,即每当移除边缘时,它就会完全遵循该操作的逻辑含义。想象一下,您有“'Poloshirt'是'red'或'yellow'或'green'”,并且您已经达到了难题的地步,这三种颜色都没有与30岁相关。这意味着无论是谁穿球衣不能30岁。实际上,“ Poloshirt”不能具有任何边缘,且端点不被这三种颜色共享。如果您递归地遵循这些推论,您将获得一个完整的解决方案。

对我无耻出售包裹感到抱歉,但是为了证明理由,我确实写了它只是为了回答这个问题。

相关问题