Пітонічний спосіб створити об’єднання всіх значень, що містяться в декількох списках


84

У мене є список списків:

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

Я хочу згладити цей список і видалити всі дублікати; або, іншими словами, застосувати набір операцій об’єднання:

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

Який найпростіший спосіб це зробити?

Відповіді:


152

set.union робить те, що ти хочеш:

>>> results_list = [[1,2,3], [1,2,4]]
>>> results_union = set().union(*results_list)
>>> print(results_union)
set([1, 2, 3, 4])

Ви також можете зробити це з більш ніж двома списками.


@sth, дякую, наприклад, але коли я запускаю його, я отримую повідомлення про помилку: Traceback (останній дзвінок останній): Файл "so_example.py", рядок 33, у? results_union = set (). union (* result_lists) TypeError: union () приймає рівно один аргумент (3 задано)
AJ.

1
@AJ: Відповідно до Documention ( docs.python.org/library/stdtypes.html#set.union ) union()підтримується лише декілька аргументів для Python версії 2.6 або новішої. Здається, ви використовуєте версію до цього, тому вам, мабуть, доведеться використовувати явний цикл: total = set(); for x in results_list: total.update(x) (s /; / \ n /)
sth

2
Ви також можете зберегти створення порожнього набору, змінивши 2-й рядок наresults_union = set.union(*(set(el) for el in results_list))
Ноель Еванс

1
@ Jean-FrançoisFabre мінімум TypeError: descriptor 'union' requires a 'set' object but received a 'list'на пітоні 3.6.
Парітош Сінгх

1
Якщо ви використовуєте, set.union(*results_list)ви прив'язуєте дескриптор методу вручну, тобто надсилаєте перший елемент results_listяк "self". Це робить деякі дивні обмеження: 1. неправильно вводить тип (тепер першим елементом повинен бути набір або екземпляр підкласу набору), і 2. об'єднання порожнього results_listбуде помилкою (неправильний результат - повинен повернути порожній встановити).
wim

12

Оскільки ви, здається, використовуєте Python 2.5 ( було б непогано згадати у своєму Q, якщо вам потрібна версія A для версій! = 2.6, до речі, поточна версія ;-) і вам потрібен список, а не набір як результат, я рекомендую:

import itertools

...

return list(set(itertools.chain(*result_list)))

itertools - це, як правило, чудовий спосіб роботи з ітераторами (а отже, і з багатьма видами послідовностей чи колекцій), і я від щирого серця рекомендую вам ознайомитися з ним. itertools.chain, зокрема, задокументована тут .


+1 Прекрасний приклад вдалого часу, щоб зануритися в чудовий itertoolsпакет.
gotgenes

@Alex дякую ... відредагував моє запитання, щоб вказати версію та зняти з себе звинувачення за те, що я відставав у версіях :) Я зроблю важливим вивчити itertools, вдячний за пропозицію.
AJ.

@AJ, ніякої провини, ми всі врешті можемо постраждати від таких обмежень (але, будь ласка, не забудьте вказати в майбутніх Q! -); itertools.chainдо речі, чудово працює і в Python 2.4.
Alex Martelli

3

Ви також можете дотримуватися цього стилю

In [12]: a = ['Orange and Banana', 'Orange Banana']
In [13]: b = ['Grapes', 'Orange Banana']
In [14]: c = ['Foobanana', 'Orange and Banana']

In [20]: list(set(a) | set(b) | set(c))
Out[20]: ['Orange and Banana', 'Foobanana', 'Orange Banana', 'Grapes']

In [21]: list(set(a) & set(b) | set(c))
Out[21]: ['Orange and Banana', 'Foobanana', 'Orange Banana']    

1

Союзи не підтримуються списками, які упорядковані, але підтримуються наборами. Перевірте set.union .


0

Я використовував наступне, щоб робити перехрестя, що дозволяє уникнути потреби в наборах.

a, b= [[1,2,3], [1,2]]
s = filter( lambda x: x in b, a)

або,

s = [ x for x in b if x in a ]

5
Чому ви взагалі хочете "уникнути потреби в наборах"? Для цього вони швидші та зрозуміліші. І ваш "x in a" виконує лінійний грубий пошук у списку кожного разу, коли ви його виконуєте. Гидота.
Peter Hansen

набори вимагають типового лиття, і лінійна швидкість непогана, якщо ви не маєте справу з великим N.
Ведмідь

3
"Типовий кастинг"? У Python? Відколи? Набори - це в основному дикти з лише клавішами, і вони використовують порівняння хешу та рівності. Використання "x у" у списку також робить порівняння рівності. Що це все про типовий кастинг?
Peter Hansen

0

розумінням:

[*{ j for i in lists for j in i }]

або

[*functools.reduce(lambda x,y: {*x, *y}, lists)]

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.