简体   繁体   English

有没有办法生成项目列表的所有唯一排列

[英]is there a way to generate all unique permutations of a list of items

I have a list of five attributes, each attribute has five different values. 我有一个包含五个属性的列表,每个属性有五个不同的值。 I want to generate the Cartesian product of them and filter all unique permutations. 我想生成它们的笛卡尔积,并过滤所有独特的排列。

Some background: 一些背景:

I need them to be my input values to solve a logic puzzle. 我需要它们作为我的输入值来解决逻辑谜题。 Where I check rules against them to find the right solution. 我在哪里检查规则以找到正确的解决方案。

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...

Perhaps a simplified example can make it clear. 也许一个简单的例子可以说清楚。

Data: 数据:

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

Cartesian Product of Data: 笛卡儿数据产品:

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

What I want: 我想要的是:

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

What I don't want: 我不想要的:

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

I don't want multiple occurrences of the same value. 我不希望多次出现相同的值。 The place matters, so it should have permutative character and that for a list of lists with five elements. 这个地方很重要,所以它应该具有排列特征,并且具有五个元素的列表列表。 I guess the output size will be enormous and maybe that isn't possible to compute so it would be nice to specify some place values which are fixed. 我猜输出大小将是巨大的,也许这是不可能计算的,所以指定一些固定的地方值会很好。 For example, I Want to set 'Dana' as a first Element name. 例如,我想将'Dana'设置为第一个元素名称。

Output: 输出:

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

Maybe you can tell me, out of curiosity, what the specific mathematical names for the concepts are, which I need? 也许你可以出于好奇,告诉我,这些概念的具体数学名称是什么,我需要哪些?


The puzzle: 谜题:

There are five friends (Dana, Ingo, Jessica, Sören, Valerie) waiting in line at the cash register of a shopping center. 五个朋友(Dana,Ingo,Jessica,Sören,Valerie)在购物中心的收银台排队等候。 They are all of different ages (26, 27, 30, 33, 35) and want to buy different tops (Blouse, Poloshirt, Pullover, Sweatshirt, T-Shirt) for themselves. 他们都是不同年龄(26,27,30,33岁,35岁),并希望自己购买不同的上衣(衬衫,Pol衫,套衫,运动衫,T恤) The tops have different colors (blue, yellow, green, red, black) and sizes (XS, S, M, L, XL) . 顶部有不同的颜色(蓝色,黄色,绿色,红色,黑色)和尺寸(XS,S,M,L,XL)

Rules: 规则:

  1. The top 'Dana' wants to buy is 'XL'. 顶级'Dana'想买的是'XL'。 Behind her (but not directly behind) is someone with a 'black' top. 在她后面(但不是直接在后面)是一个有“黑色”顶部的人。
  2. 'Jessica' waits directly in front of a person who wants to buy a 'Poloshirt'. '杰西卡'直接在一个想要购买'Poloshirt'的人面前等待。
  3. The second person in line wants to buy a 'yellow' top. 排队的第二个人想购买一个“黄色”顶部。
  4. 'T-Shirt' isn't 'red'. 'T恤'不是'红色'。
  5. 'Sören' wants to buy a 'Sweatshirt'. 'Sören'想买一件'运动衫'。 The person who waits directly in front of him is older than the one behind him. 直接在他面前等待的人比他身后的人年长。
  6. 'Ingo' needs a top in size 'L'. 'Ingo'需要顶级'L'。
  7. The last person in line is 30 years old. 排队的最后一个人是30岁。
  8. The oldest person is going to buy the top with the smallest size. 最年长的人将购买最小尺寸的顶部。
  9. The person who waits directly behind 'Valerie', wants to buy a 'red' top, which is bigger than size 'S'. 直接在'Valerie'后面等待的人想买一个比'S'大的'红色'顶部。
  10. The youngest person wants to buy a 'yellow' top. 最年轻的人想买一个“黄色”上衣。
  11. Jessica is going to buy a 'Blouse'. 杰西卡打算买一件“衬衫”。
  12. The third person waiting in line wants to buy a top of size 'M'. 排队等候的第三个人想购买一个大小为'M'的顶级人物。
  13. The 'Poloshirt' is 'red' or 'yellow' or 'green'. 'Poloshirt'是'红色'或'黄色'或'绿色'。

This will do it, but take a very long time. 这样做,但需要很长时间。 I reduced the list size because your options as requested have 24,883,200,000 permutations: 我缩小了列表大小,因为您要求的选项有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)

Output: 输出:

[('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')]

There is a fundamental problem with the approach of using permutations for the type of logic puzzle you have. 对于你所拥有的逻辑谜题类型,使用排列的方法存在一个基本问题。 The issue is not even that there are so many of them that your solver is unlikely to finish in a reasonable amount of time. 问题甚至不是因为有太多的解决方案不太可能在合理的时间内完成。 The issue is that you don't have an automated way of checking the rules against the problem: having all the possibilities in front of you is pointless unless you have a method to verify them. 问题是你没有自动检查规则来解决问题:除非你有一个方法来验证它们,否则你面前的所有可能性都是毫无意义的。

To address these issues, I have created a project called Puzzle Solvers: 为了解决这些问题,我创建了一个名为Puzzle Solvers的项目:

This is a small project that currently contains a single class of interest: puzzle_solvers.elimination.Solver . 这是一个小项目,目前包含一个感兴趣的类: puzzle_solvers.elimination.Solver This class implements most of the operations you need to solve the process-of-elimination type problem presented in your question. 此类实现了解决问题中提出的消除过程类型问题所需的大多数操作。 All of the logic is documented , and the tutorial is a walkthrough of your exact problem. 所有的逻辑都记录在案 ,并且教程是你确切的问题的演练。 I will explain the basics here, so you can understand what I did, and perhaps improve it. 我将在这里解释基础知识,这样你就可以理解我的所作所为,并且可能会改进它。

Step 1 is to recognize that position in the queue is an attribute just like age, name, etc. That means that the order is not relevant any more. 第1步是识别队列中的位置是一个属性,就像年龄,名称等一样。这意味着订单不再相关。

Step 2 is to recognize that this is a graph problem in disguise. 第2步是认识到这是伪装的图形问题。 You have 30 nodes: all the possible attributes (six of them) of each of five individuals. 您有30个节点:五个人中每个人的所有可能属性(其中六个)。 The graph starts out almost complete. 图表几乎完成。 Only the edges between attributes of a given type are missing, so you start with 375 instead of the complete 435 edges. 只缺少给定类型属性之间的边缘,因此从375开始,而不是完整的435边缘。

The final goal is to have one edge between each class of attribute among five connected components in the graph. 最终目标是在图中的五个连通组件中的每个属性类之间具有一条边。 The final number of edges is therefore 5 * 15 = 75. 因此,最终边缘数为5 * 15 = 75。

So how do you remove edges? 那么如何去除边缘? The simple rules like "'T-Shirt' isn't 'red'" are quite straightforward: just remove that edge. 像“'T恤'不是'红''这样的简单规则非常简单:只需删除那条边。 Rules like "The last person in the queue is 30 years old." 像“队列中的最后一个人已经30岁了”这样的规则。 are simple too, and more profitable in terms of edge removal. 也很简单,在边缘去除方面更有利可图。 All edges between ages that aren't 30 and position 5 are removed, as well as all edges between positions that aren't 5 and age 30. I added a couple of half-baked utility wrappers to check greater than and less than conditions and remove edges that represented impossible combinations. 去除年龄不是30和位置5之间的所有边缘,以及不是5和30岁的位置之间的所有边缘。我添加了几个半烘焙的实用程序包装来检查大于和小于条件和删除代表不可能组合的边缘。

The most important aspect of the solver is the fact that any time an edge is removed, it completely follows through with all of the logical implications of that operation. 解算器最重要的方面是这样一个事实,即每当一个边被移除时,它就会完全贯彻该操作的所有逻辑含义。 Imagine that you have "The 'Poloshirt' is 'red' or 'yellow' or 'green'" and that you have reached a point in your puzzle where none of those three colors is linked to say age 30. That means that whoever is wearing the poloshirt can not be 30 years old. 想象一下,你有''Poloshirt'是'红色'或'黄色'或'绿色'“并且你已经达到了谜题中的一个点,这三种颜色中没有一个与30岁相关联。这意味着无论谁是穿着poloshirt不能30岁。 In fact 'Poloshirt' can not have any edges with endpoints that are not shared by those three colors. 事实上,'Poloshirt'不能有任何边缘与这三种颜色不共享的端点。 If you recursively follow through with those inferences, you get a complete solution. 如果您递归地执行这些推断,您将获得完整的解决方案。

I'm sorry for the shameless sale of my package, but in justification, I did write it just to answer this question. 对于我的包裹的无耻销售,我感到很遗憾,但在理由上,我写的只是为了回答这个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM