Comment ajouter le contenu d'un itérable à un ensemble?

Réponses:

228

Vous pouvez ajouter des éléments de a listà un setcomme ceci:

>>> foo = set(range(0, 4))
>>> foo
set([0, 1, 2, 3])
>>> foo.update(range(2, 6))
>>> foo
set([0, 1, 2, 3, 4, 5])
SingleNegationElimination
la source
2
Je viens de regarder en arrière ma session d'interprétation et j'ai en fait essayé cela, mais je pensais que cela avait ajouté la liste entière en tant qu'élément de l'ensemble à cause des crochets dans la représentation de l'ensemble. Je n'avais jamais remarqué auparavant qu'ils sont représentés comme ça.
Ian Mackinnon
7
Cette représentation vous permet de la coller directement dans une session interactive, car le setconstructeur prend un itérable comme argument.
Frank Kusters
3
Notez que la représentation est juste par exemple {1, 2, 3}en Python 3 alors qu'elle était set([1, 2, 3])en Python 2.
Radon Rosborough
40

Pour le bénéfice de tous ceux qui pourraient croire, par exemple, que faire aset.add()en boucle aurait des performances compétitives avec le faire aset.update(), voici un exemple de la façon dont vous pouvez tester rapidement vos croyances avant de devenir public:

>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "a.update(it)"
1000 loops, best of 3: 294 usec per loop

>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "for i in it:a.add(i)"
1000 loops, best of 3: 950 usec per loop

>\python27\python -mtimeit -s"it=xrange(10000);a=set(xrange(100))" "a |= set(it)"
1000 loops, best of 3: 458 usec per loop

>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "a.update(it)"
1000 loops, best of 3: 598 usec per loop

>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "for i in it:a.add(i)"
1000 loops, best of 3: 1.89 msec per loop

>\python27\python -mtimeit -s"it=xrange(20000);a=set(xrange(100))" "a |= set(it)"
1000 loops, best of 3: 891 usec per loop

On dirait que le coût par élément de l'approche en boucle est plus de TROIS fois celui de l' updateapproche.

L'utilisation |= set()coûte environ 1,5 fois ce que updatefait mais la moitié de ce que fait l'ajout de chaque élément individuel dans une boucle.

John Machin
la source
14

Vous pouvez utiliser la fonction set () pour convertir un itérable en un ensemble, puis utiliser l'opérateur de mise à jour de l'ensemble standard (| =) pour ajouter les valeurs uniques de votre nouvel ensemble à l'existant.

>>> a = { 1, 2, 3 }
>>> b = ( 3, 4, 5 )
>>> a |= set(b)
>>> a
set([1, 2, 3, 4, 5])
gbc
la source
5
L'utilisation .updatea l'avantage que l'argument peut être n'importe quel itérable - pas nécessairement un ensemble - contrairement au RHS de l' |=opérateur dans votre exemple.
tzot
1
Bon point. C'est juste un choix esthétique puisque set () peut convertir un itérable en un ensemble, mais le nombre de frappes est le même.
gbc
Je n'ai jamais vu cet opérateur auparavant, j'apprécierai de l'utiliser quand il apparaîtra dans le futur; Merci!
eipxen
1
@eipxen: Il y a |pour l'union, &pour l'intersection et ^pour obtenir des éléments qui sont dans l'un ou l'autre mais pas les deux. Mais dans un langage typé dynamiquement où il est parfois difficile de lire le code et de connaître les types d'objets qui volent, j'hésite à utiliser ces opérateurs. Quelqu'un qui ne les reconnaît pas (ou ne se rend peut-être pas compte que Python autorise des opérateurs comme ceux-ci) pourrait être confus et penser que des opérations binaires ou logiques étranges sont en cours. Ce serait bien si ces opérateurs travaillaient aussi sur d'autres itérables ...
ArtOfWarfare
Ran quelques tests de temps sur ce versus .update()et ajouter des éléments individuels dans une boucle. J'ai trouvé que .update()c'était plus rapide. J'ai ajouté mes résultats à cette réponse existante: stackoverflow.com/a/4046249/901641
ArtOfWarfare
4

Juste une mise à jour rapide, timings utilisant python 3:

#!/usr/local/bin python3
from timeit import Timer

a = set(range(1, 100000))
b = list(range(50000, 150000))

def one_by_one(s, l):
    for i in l:
        s.add(i)    

def cast_to_list_and_back(s, l):
    s = set(list(s) + l)

def update_set(s,l):
    s.update(l)

les résultats sont:

one_by_one 10.184448844986036
cast_to_list_and_back 7.969255169969983
update_set 2.212590195937082
Daniel Dubovski
la source
0

Utilisez la compréhension de liste.

Court-circuiter la création d'itérable à l'aide d'une liste par exemple :)

>>> x = [1, 2, 3, 4]
>>> 
>>> k = x.__iter__()
>>> k
<listiterator object at 0x100517490>
>>> l = [y for y in k]
>>> l
[1, 2, 3, 4]
>>> 
>>> z = Set([1,2])
>>> z.update(l)
>>> z
set([1, 2, 3, 4])
>>> 

[Modifier: a manqué la partie définie de la question]

pyfunc
la source
1
Je ne vois aucun ensemble? Est-ce que je manque quelque chose?
Ian Mackinnon
-2
for item in items:
   extant_set.add(item)

Pour mémoire, je pense que l'affirmation selon laquelle "il devrait y avoir une - et de préférence une seule - façon évidente de le faire." est faux. Cela suppose que de nombreuses personnes à l'esprit technique font, que tout le monde pense de la même manière. Ce qui est évident pour une personne ne l'est pas pour une autre.

Je dirais que ma solution proposée est clairement lisible et fait ce que vous demandez. Je ne pense pas qu'il y ait de succès en termes de performance - même si j'admets que je manque peut-être quelque chose. Mais malgré tout cela, cela n'est peut-être pas évident et préférable à un autre développeur.

Jaydel
la source
Argh! La boucle for étant sur une ligne comme celle-ci est formatée dans ma réponse - je ne ferais jamais cela. Déjà.
jaydel
Vous avez tout à fait raison. J'ai édité le post pour réparer mes dégâts. Merci :)
jaydel
9
Il vous manque le point qui aset.update(iterable)boucle à la vitesse C alors que les for item in iterable: aset.add(item)boucles à la vitesse Python, avec une recherche de méthode et un appel de méthode (aarrgghh !!) par élément.
John Machin
1
Désolé, il n'a rien dit sur la performance dans sa question, donc je ne m'en suis pas inquiété.
jaydel le