Удалить ненужные элементы из списка Python - PullRequest
1 голос
/ 09 марта 2019

У меня есть список из 8 уникальных кортежей каждого размера 2. Оттуда я нахожу все возможные комбинации размера 4. Теперь у меня есть список списков, и в каждом из подсписков у меня есть ровно 4 кортежа. Что-то вроде -

[[(1, 2), (4, 5), (223, 456), (111, 345)], [...], ...]

Где основной список может быть -

[(1, 2), (4, 5), (223, 456), (111, 345), (123, 4), (23, 89), (999, 888), (895, 569)]

На самом деле это координаты точек в 2D-плоскости, и я делю 8 точек на два набора по 4 в каждом. Поэтому, если у меня есть список из 4 баллов, это означает, что у меня уже есть и остальные четыре балла. Поэтому для каждой комбинации из 4 баллов я пытаюсь удалить остальные 4 балла из списка.

Следующие работы -

def generate_all_points(points, size):
    from itertools import combinations

    all_combinations = combinations(points, size)
    return (list(all_combinations))    

def generate_4points(points):

    all_4points = generate_all_points(points, 4)
    print (len(all_4points))
    print ("ALL POINTS -\t", points)
    for point_set in all_4points:

        to_remove = list(set(points).difference(set(point_set)))
        for item in all_4points:
            if (len(set(to_remove).difference(item)) == 0):
                all_4points.remove(item)

        print ("Main -\t", point_set, "\nTo Remove -\t", to_remove)
        #all_4points.remove(list(set(points).difference(set(point_set))))
    print (len(all_4points))

Я попытался использовать только set.difference, но он переупорядочил элементы списка, и поэтому я не могу удалить их напрямую. Это я попробовал в комментариях. Что я сделал, так это нашел оставшиеся 4 балла из 8, тогда, если длина разности наборов 4 и любого элемента в списке комбинаций равна нулю, то это означает, что вместе оба набора из 4 баллов соответствуют уникальному. 8, таким образом, я удаляю этот конкретный элемент.

Есть ли способ напрямую достичь этого, может быть, в одну или две строки без петель и тому подобное?

Заранее спасибо.

1 Ответ

1 голос
/ 09 марта 2019

Лучшее решение - в первую очередь избегать создания нежелательных комбинаций.

На самом деле это довольно просто, поскольку комбинации генерируются по порядку.Нам просто нужно взять первую половину из них.Из 8 (8 * 7 * 6 * 5 / (4 * 3 * 2)) 70 комбинаций по 4 балла, поэтому мы оставляем только первые 35 комбинаций.

Демонстрация, используя числа от 1до 8 вместо кортежей для удобства чтения:

from itertools import combinations, islice

l = [1, 2, 3, 4, 5, 6, 7, 8]

nb_combinations = 70
print(list(islice(combinations(l, 4), nb_combinations//2)))

Вывод:

[(1, 2, 3, 4), (1, 2, 3, 5), (1, 2, 3, 6), (1, 2, 3, 7), (1, 2, 3, 8), 
(1, 2, 4, 5), (1, 2, 4, 6), (1, 2, 4, 7), (1, 2, 4, 8), (1, 2, 5, 6), 
(1, 2, 5, 7), (1, 2, 5, 8), (1, 2, 6, 7), (1, 2, 6, 8), (1, 2, 7, 8),
(1, 3, 4, 5), (1, 3, 4, 6), (1, 3, 4, 7), (1, 3, 4, 8), (1, 3, 5, 6),
(1, 3, 5, 7), (1, 3, 5, 8), (1, 3, 6, 7), (1, 3, 6, 8), (1, 3, 7, 8),
(1, 4, 5, 6), (1, 4, 5, 7), (1, 4, 5, 8), (1, 4, 6, 7), (1, 4, 6, 8),
(1, 4, 7, 8), (1, 5, 6, 7), (1, 5, 6, 8), (1, 5, 7, 8), (1, 6, 7, 8)]

Вы можете видеть, что все эти 35 комбинаций содержат первое значение 1, поэтому мы уверены, что ни одна изони являются дополнением к другому из этого набора.101

Итак, ваша функция может быть записана:

from itertools import combinations, islice

def generate_4points(points):
    # we only keep the first 35 combinations out of 70
    return list(islice(combinations(points, 4), 35))
...