【问题标题】:Expanding and diminishing a list of sets扩大和缩小集合列表
【发布时间】:2018-05-25 07:10:32
【问题描述】:

好的,这是一个很难解释的问题。正是我解释它的困难使得创建我想要的循环变得困难。

考虑一下这个 10 组的列表

my_list_of_sets = [ 
{0,1,2,3,4,5,7,9},
{0,1,2,4,5,6,7}, 
{0,1,2,3,4,8,9},
{1,3,4,5,6,7,8,9}, 
{1,2,3,4,5,6}, 
{3,4,5,6,7,8,9}, 
{1,2,3,5,6,8,9},
{2,3,4,5,6,7,8}, 
{2,5,6,7,8,9}, 
{3,4,6,7,8,9}]

我想应用以下类型的规则来扩展这些列表的交集。

规则 1:my_list_of_sets[0] 可以与索引为 0,1,2,3,4,5,7,9 的 my_list_of_sets 相交。

规则 2:my_list_of_sets[1] 可以与索引为 0,1,2,4,5,6,7 的 my_list_of_sets 相交

RuleX:my_list_of_sets[x] 可以与索引在 my_list_of_sets[x] 中的 my_list_of_sets 相交

RuleN:My_list_of_sets[1] 不能与 my_list_of_sets[3] 或 my_list_of_sets[8] 或 my_list_of_sets[9] 共存。

并以递归方式执行此操作,直到我展开可以“共存”的集合的输出列表。

我执行的循环流程

my_output_list_item = my_list_of_sets[0] & my_list_of_sets[0]

{0,1,2,3,4,5,7,9}

my_output_list_item = my_output_list_item & my_list_of_sets[1] #Skipped no index

{1,2,4,5,7}

然后我可以继续与索引 2,4,5,7 相交...

my_output_list_item = my_output_list_item & my_list_of_sets[2] 

{0,1,2,4}

my_output_list_item = my_output_list_item & my_list_of_sets[4]  

{1,2,4}

直到我将 my_list_of_sets[0] 作为索引进入 my_list_of_sets 并找到一个没有“异议”的集合 {1,2,4}。抱歉,我想不出一个更好的词来表示可以相交的集合。

问题 1 您会注意到,如果我的循环的第一次迭代是任意的 my_list_of_sets[0] & my_list_of_sets[1] 索引 3 在第一次迭代中被删除。如果第一遍是任意的 my_list_of_sets[0] 和 my_list_of_sets[2],我会得到不同的结果。

my_output_list_item = my_list_of_sets[0] & my_list_of_sets[2] #Skipped one index

{0,1,2,3,4,9}

my_output_list_item = my_output_list_item & my_list_of_sets[3]

{1,3,4,9}

my_output_list_item = my_output_list_item & my_list_of_sets[4]

{1,3,4}

my_output_list_item = my_output_list_item & my_list_of_sets[1]

{1,4}

根据开始交叉点的索引,我得到了 {1,2,4} 和 {1,4}。 这意味着我的输入数据顺序已与结果相关,并且它是一个集合,没有固有顺序。

出于这个原因,我尝试通过使用滚动切片窗口沿着集合进行并执行所有起始索引的交集来解决问题 1。 这是我到目前为止的代码。

my_output_list = set()
for i in range(len(my_list_of_sets)):
    set_as_list = list(my_list_of_sets[i])  #need a list here because it will be indexed from various offsets
    for slice_index in range(0, len(set_as_list)):  # the index is used to make sure all items are started with every other bd
        new_item = my_list_of_sets[i]
        for bd in set_as_list[slice_index::] + set_as_list[:slice_index:]:
            if bd in new_item:  # need this if statement as new_item is getting smaller each loop of bd.
                new_item = new_item.intersection(my_list_of_sets[bd])
        my_output_list.add(frozenset(new_item))

这将枚举到 15 个集合的 my_output_list。

问题 2: 但是这段代码仍然遗漏了一些组合

my_output_list_item = my_list_of_sets[0] 
my_output_list_item = my_output_list_item & my_list_of_sets[2] #Skipped one index
my_output_list_item = my_output_list_item & my_list_of_sets[4] #Skipped one index
my_output_list_item = my_output_list_item & my_list_of_sets[1]

{1,2,4}

my_output_list_item = my_list_of_sets[0] 
my_output_list_item = my_output_list_item & my_list_of_sets[2] #Skipped one index
my_output_list_item = my_output_list_item & my_list_of_sets[9] #Skipped two index
my_output_list_item = my_output_list_item & my_list_of_sets[3]
my_output_list_item = my_output_list_item & my_list_of_sets[4]

{3,4}

my_output_list_item = my_list_of_sets[0] 
my_output_list_item = my_output_list_item & my_list_of_sets[2] #Skipped one index
my_output_list_item = my_output_list_item & my_list_of_sets[0] #Skipped three index
my_output_list_item = my_output_list_item & my_list_of_sets[1]
my_output_list_item = my_output_list_item & my_list_of_sets[2]
my_output_list_item = my_output_list_item & my_list_of_sets[4]

{1,2,4} 等等。

我相信这个缺失的{3,4} 是由于滚动切片bd 的索引值顺序增加而忽略了一些可能的组合。

因此,虽然我已经拥有循环迭代 0 的滚动切片 bd,但我认为我还需要一个 itertools 来遍历 my_list_of_sets[0] 的所有组合中的索引。

几处编辑。我不能暴力破解所有组合并删除非法组合。它是 len 100 列表,即 100^100 个组合,而计算机无法做到。 我知道我的答案可能在于 itertools,但我并没有想象它适用于长度大于 2 的列表的产品。

【问题讨论】:

  • 这里对您的问题进行了更简洁的表述:您正在寻找可以共存的最大集合组(并打印出该组中的集合)。如果每个集合包含组中所有其他集合的索引,则一组集合可以共存。对吗?
  • 是的。踢球者是您碰巧组装集合的递归序列会影响结果。
  • 不清楚你的目标是什么。我认为这包含了您的大部分规则:all(all(my_list_of_sets[i] & u for i in u) for u in my_list_of_sets)。但我不明白 RuleN 是关于什么的。 FWIW,这看起来像 Block Design 问题。
  • 规则 N 也在交叉点中实现,但它会使代码不稳定,具体取决于输入交叉点的索引序列。您对块设计确实是正确的,bd 计数器是一个线索。让我研究一下那个 wiki 条目。
  • 错字。集合可以与自身存在。会修复的。

标签: python loops set slice


【解决方案1】:

从 AI constraint satisfaction 的角度来看可能值得一试。如果您计算一个集合排除了多少东西,以及有多少集合排除了该集合,您可以从约束最小的开始着手。

对于上面的示例(右轴是该集合排除了多少东西,底轴是排除了该集合的多少东西)

   0 1 2 3 4 5 6 7 8 9
0: 1 1 1 1 1 1 0 1 0 1 | 2
1: 1 1 1 0 1 1 1 1 0 0 | 3
2: 1 1 1 1 1 0 0 0 1 1 | 3
3: 0 1 0 1 1 1 1 1 1 1 | 2
4: 0 1 1 1 1 1 1 0 0 0 | 4
5: 0 0 0 1 1 1 1 1 1 1 | 3
6: 0 1 1 1 0 1 1 0 1 1 | 3
7: 0 0 1 1 1 1 1 1 1 0 | 3
8: 0 0 1 0 0 1 1 1 1 1 | 4
9: 0 0 0 1 1 0 1 1 1 1 | 4
   - - - - - - - - - - 
   7 4 3 2 2 2 3 2 3 3 

约束总和:

  • 0 = 9
  • 1 = 7
  • 2 = 6
  • 3 = 4
  • 4 = 6
  • 5 = 5
  • 6 = 6
  • 7 = 5
  • 8 = 7
  • 9 = 7

那么,既然你已经解决了你的限制条件:

  1. 从您的最小约束集开始:3
  2. 3灭0,2,8
  3. 添加一个你的下一个最小约束仍然有效:5
  4. 5灭1,9,2
  5. 添加下一个最小约束仍然有效:7
  6. 7灭4和6
  7. 没有更多有效的

剩下的一组是:3、5、7

【讨论】:

  • 我早上可以试试这个。我担心的是我可以很快得到最满意的组合,这是人工智能模式匹配的理想选择;但我还需要列举奇怪的那些,可能从最受约束的开始,然后反弹到受约束的中间,然后看看剩下的是什么。我将在明天对其进行编码并报告调查结果。我还有一个问题是我不知道我何时拥有正确的最大组合数。
  • 是的!我认为经典的方法是在(选择不是下一个最不受约束的选项的概率)中添加一些随机化并运行几次,然后获得最好的结果。多次运行应该仍然比蛮力快得多。
  • 好的,因为这可以得到多达 12k 的组合,甚至不触及所有角落,它变得难以管理,我不会手动查看输出。我想我需要寻找正交组合,因为我知道它们存在于源数据中。
猜你喜欢
  • 1970-01-01
  • 2013-08-21
  • 2020-03-12
  • 2017-01-12
  • 1970-01-01
  • 2017-03-17
  • 1970-01-01
  • 1970-01-01
  • 2022-06-15
相关资源
最近更新 更多