Установка понимания в Python и тестирование на членство в создаваемом наборе
Это на самом деле вопрос о семантике множественного понимания, но сначала мне нужно объяснить контекст. Я пытаюсь создать новый набор кортежей, в котором парное значение в таупе является уникальным независимо от порядка значений в паре. Упрощение моей реальной программы, что у меня есть что-то вроде {(1, 2), (2, 1), (3, 4)}
и я хотел бы получить {(1, 2), (3, 4)}
Я пытался сделать что-то вроде этого:
oldSet = {(1, 2), (2, 1), (3, 4)}
newSet = set()
newSet = {(val1, val2) for (val1, val2) in oldSet if not (val2, val1) in newSet}
Тем не мение, newSet
является {(1, 2), (2, 1), (3, 4)}
, подразумевая, что что-то не так с моим условным выражением. Мое понимание понимания предполагает, что вышеизложенное является синтаксическим сахаром для чего-то вроде этого:
newSet = set()
for (val1, val2) in oldSet:
if not (val2, val1) in newSet:
newSet.add((val1, val2))
Эта традиционная циклическая структура работает (newSet
является {(1, 2), (3, 4)}
). Есть ли что-то в понимании, которое заставляет условное оцениваться раньше? newSet
есть ли участники? Я довольно новичок в Python, поэтому мне интересно, есть ли что-то тонкое, что я пропускаю.
Спасибо!
2 ответа
Ты не понял; Понимание множества - это отдельное выражение, отдельное от назначения. Выражение производит новый set()
объект, который затем будет назначен newSet
, заменив старый set()
объект у вас был.
Таким образом, когда вы повторяете и строите набор, предыдущий и отдельный set()
объект привязан к newSet
остается пустым. В действительности, установленное понимание делает это:
newSet = set()
_result = set()
for (val1, val2) in oldSet:
if not (val2, val1) in newSet:
result.add((val1, val2))
newSet = _result
Вы можете использовать побочные эффекты, чтобы изменить отдельный набор во время итерации:
seen = set()
newSet = {(val1, val2) for (val1, val2) in oldSet
if not ((val2, val1) in seen or seen.add((val1, val2))}
Это использует seen
для отслеживания того, что уже было обработано и содержит кортеж, если оба условия выполняются:
- обратное еще не было видно раньше,
seen.add()
операция для кортежа возвращает ложное значение. посколькуseen.add()
всегда возвращаетсяNone
, это всегда будет так.
Обратите внимание, что теперь он создает один и тот же набор дважды, так что вы можете также сделать обычный цикл и покончить с этим:
newSet = set()
for (val1, val2) in oldSet:
if not (val2, val1) in newSet:
newSet.add((val1, val2))
Поскольку ваши кортежи состоят только из двух значений, вы также можете использовать сортировку здесь; любая пара кортежей (a, b), (b, a)
имеет одну уникальную сортировку, в конце концов:
newSet = {tuple(sorted(t)) for t in oldSet}
Рабочая альтернатива:
newSet = { tuple(sorted(t)) for t in oldSet }
Ваше решение проверяет наличие кортежа в создаваемом наборе, но имя еще не связано со значением. Это будет, когда постижение закончится.