簡體   English   中英

如何根據Python中的一個布爾字段保持順序創建元組列表的所有排列

[英]How to create all permutations of a list of tuples depending on one boolean field keeping order in Python

假設我有一個輸入作為這樣的元組列表:

[('a', True),
 ('b', False),
 ('c', True),
 ('d', False)] 

每個具有True作為第二個參數的元組都被認為是可選的。

  • 列表中的元組數量是任意的
  • 第一個值的值是任意的,必須保留

現在,我想通過以下方式置換此結構:

  • 輸出應為元組列表的列表
  • 每個元組列表都是唯一的
  • 列表在存在或不存在的可選元組上有所區別
  • False元組不變(消失)
  • 列表內元組的順序不變
  • 元組的順序不變
  • 元組列表可以按任何順序排列

因此,以上示例的輸出應如下所示:

[[('a', True),
  ('b', False),
  ('c', True),
  ('d', False)],

 [('b', False),
  ('c', True),
  ('d', False)],

 [('a', True),
  ('b', False),
  ('d', False)],

 [('b', False),
  ('d', False)]]

有什么想法如何以一種優雅的方式解決這個問題? 我嘗試遞歸,但無法完成。

我不確定是否有特別優雅的方法。 從概念上講,您需要計算可選元素的功效集,然后以滿足您要求的方式將其與非可選元素合並。 這是一種方法:

import itertools
a = [('a', True), ('b', False), ('c', True), ('d', False)]
optional_count = sum(optional for x, optional in a)
for include in itertools.product([True, False], repeat=optional_count):
    include_iter = iter(include)
    print([
        (x, optional)
        for x, optional in a
        if not optional or next(include_iter)
    ])

印花

[('a', True), ('b', False), ('c', True), ('d', False)]
[('a', True), ('b', False), ('d', False)]
[('b', False), ('c', True), ('d', False)]
[('b', False), ('d', False)]

該循環遍歷所有元組,指示是否包括可選元素:

True, True
True, False
False, True
False, False

打印語句中的列表理解包括所有非可選元素,對於可選元素,請查看include中的下一個可用元素。

實際上,我剛剛想到了一個不錯的遞歸解決方案:

def choices(a):
    if not a:
        yield []
        return
    head, *tail = a
    if head[1]:
        yield from choices(tail)
    for tail_choice in choices(tail):
        yield [head] + tail_choice

這會在所有元組列表上創建一個惰性生成器:

>>> list(choices(a))
[[('b', False), ('d', False)],
 [('b', False), ('c', True), ('d', False)],
 [('a', True), ('b', False), ('d', False)],
 [('a', True), ('b', False), ('c', True), ('d', False)]]

您可以通過復制到目前為止的選擇列表來做出選擇,然后將新值附加到副本中,然后將其與到目前為止的選擇列表合並。

很抱歉得到這個可怕的解釋,但是我現在無法提出更好的建議。 如果可以提出更好的建議,請隨時進行編輯。 否則,我希望下面的圖表和代碼可以更好地解釋我的解決方案。

                                        []
                    -------------------------------------------
                   []                                        [0]
       ----------------------------                ---------------------------
       []                       [1]                [0]                  [0, 1]
       ...                      ...                ...                  ...

基本思想是遍歷所有項目,克隆所有部分解決方案,然后將項目追加到克隆的解決方案中。

def choose(arr):
    res = [[]]

    for t in arr:
        if t[1]:
            # make a copy of all found solutions
            clone = [list(c) for c in res]

            # append the new value to the original solutions
            for l in res:
                l.append(t)

            # merge solution-list with the list of copies
            res += clone
        else:
            # non-optional element => just add the element to all solutions
            for l in res:
                l.append(t)

    return res

輸出:

print('\n'.join(str(l) for l in choose([('a', True), ('b', False), ('c', True), ('d', False)])

[('a',True),('b',False),('c',True),('d',False)]
[('b',False),('c',True),('d',False)]
[('a',True),('b',False),('d',False)]
[('b',False),('d',False)]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM