2017-03-08 1 views
1

Par exemple, quel est le itertools.chain() équivalent de:Comment puis-je générer des chaînes itertools uniques?

set.union({1,2,3},{3,4,2,5},{1,6,2,7}) 

(évidemment qui retourne un générateur, plutôt qu'un ensemble)

+0

Pouvez-vous fournir des entrées et des sorties? Ce n'est pas clair ce que vous demandez de la terminologie utilisée. –

+0

Je ne pense pas que vous puissiez le faire avec un itérable: il doit y avoir un moyen de voir si l'élément courant existe déjà dans la sortie, donc il faut stocker la sortie et l'ajouter en cours de route. – Evert

Répondre

4

Il n'y a rien à itertools qui le fera pour vous directement. Pour éviter de générer des doublons, vous devez garder une trace de ce que vous avez déjà produit, et la manière évidente de le faire est d'utiliser un ensemble. Voici une simple enveloppe autour itertools.chain() qui fait que:

from itertools import chain 

def uniq_chain(*args, **kwargs): 
    seen = set() 
    for x in chain(*args, **kwargs): 
     if x in seen: 
      continue 
     seen.add(x) 
     yield x 

... et voilà en action:

>>> list(uniq_chain(range(0, 20, 5), range(0, 20, 3), range(0, 20, 2))) 
[0, 5, 10, 15, 3, 6, 9, 12, 18, 2, 4, 8, 14, 16] 

Sinon, si vous préférez composer une solution à partir de blocs de construction plus petite (qui est une approche plus souple et « itertoolsy » façon de le faire), vous pouvez écrire une fonction d'usage général uniq() et le combiner avec chain():

def uniq(iterable): 
    seen = set() 
    for x in iterable: 
     if x in seen: 
      continue 
     seen.add(x) 
     yield x 

en action:

>>> list(uniq(chain(range(0, 20, 5), range(0, 20, 3), range(0, 20, 2)))) 
[0, 5, 10, 15, 3, 6, 9, 12, 18, 2, 4, 8, 14, 16] 
0

vous pouvez faire quelque chose comme ceci:

def chain_unique(*args): 
    seen = set() 
    yield from (v for v in chain(*args) if v not in seen and not seen.add(v)) 
+1

Cela fonctionne, mais je pense que ce n'est pas pythonique de mettre autant de logique dans une ligne de code – wim