Приоритетные упорядоченные комбинации списка

1

Прежде всего, должны быть созданы все возможные комбинации списка. Это простая проблема - благодаря itertools.combinations. Затем комбинации должны быть упорядочены в соответствии со следующими приоритетами: первый элемент исходного списка имеет наивысший приоритет, второй - второй приоритет и так далее. Обратите внимание, что любая группировка более низких приоритетов не может быть выше любого более высокого приоритета. Тривиальный пример:

input = ['A', 'B']
output = [['A', 'B'], ['A'], ['B']]

Пример из 3 элементов:

input = ['A', 'B', 'C']
output = [['A', 'B', 'C'], ['A', 'B'], ['A', 'C'], ['A'], ['B', 'C'], ['B'], ['C']]

Вопрос. Учитывая список любых элементов, как найти список всех возможных комбинаций, упорядоченных по приоритетам, как описано выше?

  • 1
    что ты уже испробовал?
  • 1
    Какой у Вас вопрос?
Показать ещё 1 комментарий
Теги:
list
combinations

4 ответа

2
Лучший ответ

Добавление элемента в список всегда увеличивает приоритет. Мы можем вести список списков и рекурсивно добавлять худшие элементы, чтобы получить желаемый порядок.

cs = ["A", "B", "C"]


def subsets(xs):
    res = [[]]
    for x in xs[::-1]:
        res = [[x] + r for r in res] + res

    return res[:-1]


# [["A", "B", "C"], ["A", "B"], ["A", "C"], ["A"], ["B", "C"], ["B"], ["C"]]

Во время выполнения res выглядит следующим образом:

[[]]
[["C"],[]]
[["B","C"],["B"],["C"],[]]
...

В качестве альтернативы вы можете положиться на itertools.product чтобы получить ленивое решение.

from itertools import product


def lazy_subsets(xs):
    for ix in product(*([[True, False]] * len(xs))):
        yield [x for x, b in zip(xs, ix) if b]


res = list(lazy_subsets(cs))[:-1]

Здесь каждый ix представляет собой список bool который используется в качестве булевой маски для фильтрации xs. Порядок, в котором product дает ix совпадает с порядком на подмножествах xs который дает приоритеты исходным элементам.

  • 0
    Я был бы рад услышать, как улучшить этот ответ.
  • 0
    как ваше решение itertools.product - очень лаконично ...
Показать ещё 1 комментарий
0

Немного неуклюже, но это работает с использованием itertools.combinations...

import itertools

def iter(string):
    raw_result = []
    result = []
    for i in range(len(string), -1, -1):
        for y in itertools.combinations(string, i):
            if len(y) > 0:
                raw_result.append(list(y))
    for s in string:
        for bit in raw_result:
            if s == bit[0]:
                result.append(bit)
    return result
print(iter('ABCD'))
0

Вы можете сортировать комбинации с помощью функции приоритета, которая определяется как отсортированный список исходных индексов элементов комбинации (нижний индекс означает более высокий приоритет), дополненный бесконечностями в конце (так как мы хотим дать комбинациям более высокой длины шанс против более низких длины):

from itertools import combinations

lst = ['A', 'B', 'C']
index = {l: i for i, l in enumerate(lst)}

def priority(c):
    return sorted([index[x] for x in c]) + [float('inf')] * (len(lst) - len(c))


result = sorted([c for i in range(1, len(lst) + 1) for c in combinations(lst, i)], key=priority)
print(result)
# [('A', 'B', 'C'), ('A', 'B'), ('A', 'C'), ('A',), ('B', 'C'), ('B',), ('C',)]
0

Вы можете создать набор полномочий, а затем просто отсортировать каждый элемент в соответствии с вашим приоритетом:

from itertools import combinations, chain


class OrderedList:
    indices = {}

    def __init__(self, lst):
        self.lst = lst

    def __lt__(self, other):
        lt = all(OrderedList.indices[s] <= OrderedList.indices[o] for s, o in zip(self.lst, other.lst)) and len(self.lst) >= len(other.lst)
        return lt


def power_set(iterable):
    s = list(iterable)
    r = chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))
    return map(list, (e for e in r if e))


original = ['A', 'B', 'C']
OrderedList.indices = {e: i for i, e in enumerate(original)}

result = sorted(power_set(original), key=OrderedList)
print(result)

original = ['A', 'B']
result = sorted(power_set(original), key=OrderedList)
print(result)

Выход

[['A', 'B', 'C'], ['A', 'B'], ['A', 'C'], ['A'], ['B', 'C'], ['B'], ['C']]
[['A', 'B'], ['A'], ['B']]

Ещё вопросы

Сообщество Overcoder
Наверх
Меню