Python удаляет кортежи из списка, удовлетворяющие заданным условиям

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

Это плохое объяснение, например:

[(0,1,2), (0,2,1), (0,0,1)] 

удалить (0,1,2) или (0,2,1)

Я хочу иметь возможность перебирать список и удалять любые кортежи, удовлетворяющие следующим условиям:

len(tuple1) == len(tuple2) and sum(tuple1) == sum(tuple2)

но оставьте в списке либо tuple1, либо tuple2.

Я пытался:

for t1 in list:
    for t2 in list:
           if len(t1) == len(t2) and sum(t1) == sum(t2):
               list.remove(t1) 

но я уверен, что это удалит все кортежи, и консоль разбилась.

Также очень небезопасно использовать коллекцию повторять и модифицировать одновременно, так что это не лучший вариант.

Willem Van Onsem 08.11.2018 22:11

что, если кортеж [a, b, c, d, e, a '] - должен оставаться только a или a' или вы проверяете только соседние?

Patrick Artner 08.11.2018 22:13
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
187
7

Ответы 7

Наверное, проще просто составить новый список, соответствующий вашим условиям.

old_list = [(0,1,2), (0,2,1), (0,0,1)]
new_list = []
for old_t in old_list:
    for new_t in new_list:
        if len(old_t) == len(new_t) and sum(old_t) == sum(new_t):
            break
    else:
        new_list.append(old_t)

# new_list == [(0, 1, 2), (0, 0, 1)]

Python for имеет пункт else.

Nizam Mohamed 08.11.2018 22:39

@NizamMohamed Я всегда забываю об этом, исправлено в редактировании, спасибо!

mVChr 09.11.2018 21:01

По сути, это «фильтр уникальности», но там, где мы указываем функцию f, и только если этот f(x) встречается во второй раз, мы отфильтровываем этот элемент.

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

def uniq(iterable, key=lambda x: x):
    seen = set()
    for item in iterable:
        u = key(item)
        if u not in seen:
            yield item
            seen.add(u)

Затем мы можем использовать этот фильтр как:

result = list(uniq(data, lambda x: (len(x), sum(x))))

Например:

>>> list(uniq(data, lambda x: (len(x), sum(x))))
[(0, 1, 2), (0, 0, 1)]

Здесь мы всегда будем сохранять первое вхождение «дубликатов».

Вы также можете использовать groupby для группировки элементов по sum и len и выборки по 1 элементу из каждой группы для создания нового списка:

from itertools import groupby

def _key(t):
    return (len(t), sum(t))

data = [(0, 1, 2), (0, 2, 1), (0, 0, 1), (1, 0, 0), (0, 1, 0), (3, 0, 0, 0)]
result = []
for k, g in groupby(sorted(data, key=_key), key=_key):
    result.append(next(g))

print(result)
# [(0, 0, 1), (0, 1, 2), (3, 0, 0, 0)]

Мне это нравится, но не хватает длины.

mVChr 08.11.2018 22:18

@mVChr Я это пропустил. Фиксированный :)

slider 08.11.2018 22:21

Сложность вашей проблемы в основном связана с тем, что у вас есть два независимых фильтра, которые вы хотите реализовать. Хороший способ фильтрации данных с такими требованиями - использовать groupby. Однако, прежде чем вы сможете это сделать, вам нужно сначала отсортировать. Поскольку вы обычно сортируете по одному ключу, вам нужно будет дважды выполнить сортировку, прежде чем вы сможете сгруппировать:

from itertools import groupby

def lensumFilter(data):
    return [next(g) for _, g in groupby(sorted(sorted(data, key = len), key = sum), 
        key = lambda x: (len(x), sum(x)))]

>>> print(lensumFilter( [(0, 1, 2), (0, 2, 1), (0, 0, 1)] )
[(0, 0, 1), (0, 2, 1)]

>>> print(lensumFilter( [(0, 1, 2), (0, 2, 1), (0, 0, 0, 3), (0, 0, 1)] )
[(0, 0, 1), (0, 2, 1), (0, 0, 0, 3)]

>>> print(lensumFilter( [(0, 1, 2), (0, 2, 2), (0, 4), (0, 0, 0, 5), (0, 0, 3)] )
[(0, 1, 2), (0, 4), (0, 2, 2), (0, 0, 0, 5)]

Обратите внимание, что если вы измените способ работы сортировки, вы измените то, как будет выглядеть вывод. Например, я отсортировал по длине, а затем суммировал, чтобы мои результаты были в порядке по сумме (сначала наименьшая сумма), а затем по порядку по длине (сначала наименьшее количество элементов) в группировках сумм. Вот почему (0, 1, 2) предшествует (0, 4), а (0, 4) предшествует (0, 2, 2).

Позвольте предложить несколько иное решение. Обратите внимание, что я бы использовал это не для разового сценария, а для реального проекта. Потому что ваш [(0, 0, 1)] на самом деле представляет собой нечто логическое / физическое.

set(..) удаляет дубликаты. Как насчет того, чтобы использовать это? Единственное, о чем следует помнить, - это то, что необходимо изменить хеш-значение и равенство элементов.

class Converted(object):
    def __init__(self, tup):
        self.tup = tup
        self.transformed = len(tup), sum(tup)

    def __eq__(self, other):
        return self.transformed == other.transformed

    def __hash__(self):
        return hash(self.transformed)

inp = [(0,1,2), (0,2,1), (0,0,1)]
out = [x.tup for x in set(map(Converted, inp))]
print(out)
# [(0, 0, 1), (0, 1, 2)]

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

tup_remove = (0,2,1)
list(filter(lambda current_tup: not (sum(tup_remove) == sum(current_tup) and len(tup_remove) == len(current_tup))

Для лучшей читаемости и расширяемости я бы посоветовал вам использовать функцию:

def not_same_sum_len_tuple(tup_to_check, current_tuple):
    """Return True when not same sum AND same length"""
    same_sum = sum(tup_to_check) == sum(current_tuple) # Check the sum
    same_len = len(tup_remove) == len(current_tuple) # Check the length
    return not (same_sum and same_len)

tup_remove = (0,2,1)
list(filter(lambda current_tup: not_same_sum_len_tuple(tup_remove, current_tup), tup_list))

Это более простое решение, но оно может быть неэффективным. Просто сделайте dict с (len(t), sum(t)) в качестве ключей и tuple в качестве значений. Остается последний tuple.

lst = [(0,1,2), (0,2,1), (0,0,1)]
d = {(len(t), sum(t)): t for t in lst}
list(d.values())

В одну строку;

list({(len(t), sum(t)): t for t in lst}.values())

Чтобы сделать его эффективным, просто запомните len и sum.

from functools import lru_cache
mlen, msum = (lru_cache(maxsize=None)(f) for f in (len, sum))
list({(mlen(t), msum(t)): t for t in lst}.values())

Другие вопросы по теме