Как вы можете удалить списки надмножеств из списка списков в Python?

У меня есть список списков в Python, например:

[[1,2,3],[2,3],[2,4,3],[4,5],[5]]

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

[[2,3],[5]]

Как я могу это сделать?


person apriori    schedule 01.06.2018    source источник


Ответы (4)


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

def get_minimal_subsets(sets):
    sets = sorted(map(set, sets), key=len)
    minimal_subsets = []
    for s in sets:
        if not any(minimal_subset.issubset(s) for minimal_subset in minimal_subsets):
            minimal_subsets.append(s)

    return minimal_subsets

l = [[1,2,3],[2,3],[2,4,3],[4,5],[5]]

print(get_minimal_subsets(l))  # [{5}, {2, 3}]
person Olivier Melançon    schedule 01.06.2018
comment
Ваш код красивый и чистый. Если вы посмотрите на мой ответ, вы можете удалить цикл из минимальных_подмножеств на итерацию, удалив соответствующие надмножества на каждой итерации. Мое предположение состоит в том, что это более эффективно, чем стоимость нарезки каждого цикла, но я не засекал время, чтобы быть уверенным. - person AnilRedshift; 01.06.2018

Вы можете использовать понимание списка:

d = [[1,2,3],[2,3],[2,4,3],[4,5],[5]]
new_d = [i for i in d if not any(all(c in i for c in b) and len(b) < len(i) for b in d)]

Выход:

[[2, 3], [5]]
person Ajax1234    schedule 01.06.2018

Вот:

super=[[1,2,3],[2,3],[2,4,3],[4,5],[5]]
subset=[s for s in super if not any(set(s).issuperset(set(i)) and len(s)>len(i) for i in super)]

Выход:

>>> subset
[[2, 3], [5]]
person Tin Luu    schedule 01.06.2018

Я пришел к той же идее, что и @Olivier Melançon. Вы можете использовать порядок возрастания, чтобы отбросить подмножества и выполнить это за O (n ^ 2) * O (вычисление подмножества).

input = [[1,2,3],[2,3],[2,4,3],[4,5],[5]]
sets = [set(x) for x in input]
sets.sort(key=len)

subsets = []
while sets != []:
    cur = sets[0]
    subsets.append(cur)
    sets = [x for x in sets[1:] if not cur <= x]

output = [list(x) for x in subsets]
print(output)
person AnilRedshift    schedule 01.06.2018
comment
Вместо нарезки вы должны сортировать в обратном порядке и выталкивать последний элемент, который равен O (1). Сначала: sets.sort(key=len, reverse=True) Затем cur = sets.pop(); subsets.append(cur). Это позволяет удалить слайсинг из понимания списка: sets = [x for x in sets if not cur <= x]. - person Olivier Melançon; 01.06.2018
comment
Как бы вы поступили по-другому: сохранили суперсеты, но выбросили подсеты? Я делаю это с помощью лямбда-функции, но получаю огромный удар по производительности, поскольку основной список становится больше: clean_list = filter(lambda f: not any(set(f) < set(g) for g in main_list), main_list) - person marillion; 07.06.2018