J'ai une liste imbriquée
my_list = [] for i in range(10000): # not necessary 10000, any huge number my_list.append(ff(yy1))
Je veux faire toutes les permutations possibles d'éléments dans les sous-listes sans aller au-delà de la sous-liste correspondante. Les résultats attendus sont des variantes de quelque chose comme ceci:
def swap(x): if isinstance(x, list): res = np.random.choice(x, len(x), replace = False) return [list(map(ff, res))] else: return x
Chaque élément à conserver est conservé entre crochets.
Je Worte ce générateur:
[['c', 'b', 'a'], ['d'], ['f', 'e', ['g', ['i', 'h']]]] [['d'], ['a', 'b', 'c'], ['f', 'e', [['h', 'i'], 'g']]]
Il donne des variantes aléatoires du résultat attendu, mais je dois les rassembler toutes. Comment pourrais-je le faire? Dois-je faire:
x = [['a', 'b', 'c'], ['d'], ['e', 'f', ['g', ['h', 'i']]]]
Et puis appliquer une fonction unique à ma_liste pour en sélectionner des uniques, ou il y a une autre option?
3 Réponses :
Pas particulièrement pythonique, mais je l'aborderais en trouvant des permutations des index, comme on le voit ici:
from itertools import permutations mylist= [[1], [1,2], [1,2,3]] combinations = list(permutations([i for i in range(len(mylist))])) print(combinations) for item in combinations: print([mylist[item[i]] for i in range(len(mylist))]) Output: [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)] [[1], [1, 2], [1, 2, 3]] [[1], [1, 2, 3], [1, 2]] [[1, 2], [1], [1, 2, 3]] [[1, 2], [1, 2, 3], [1]] [[1, 2, 3], [1], [1, 2]] [[1, 2, 3], [1, 2], [1]]
Mais il n'y a pas de permutations pour les éléments dans les sous-listes. Par exemple, il doit également y avoir quelque chose comme [3, 1, 2] [2, 1] [1]
et [1] [2, 1, 3] [1, 2]
Définissez-le comme une fonction, puis appliquez-le également aux sous-listes
Avez-vous envisagé d'utiliser itertools?
Il existe des outils de combinaison et de permutation explicites disponibles
À partir de la documentation :
itertools.permutations (itérable [ r])
Renvoie une longueur de r successive permutations d'éléments dans l'itérable.
Si r n'est pas spécifié ou vaut None, alors r prend par défaut la longueur du itérables et toutes les permutations complètes possibles sont générées.
Les permutations sont émises dans l'ordre de tri lexicographique. Donc, si l'entrée iterable est trié, les tuples de permutation seront produits en trié commande.
Les éléments sont traités comme uniques en fonction de leur position et non de leur évaluer. Donc, si les éléments d'entrée sont uniques, il n'y aura pas de répétition valeurs dans chaque permutation.
itertools.combinations (iterable, r)
Renvoie des sous-séquences de r length des éléments de l'itérable d'entrée.
Les combinaisons sont émises dans l'ordre de tri lexicographique. Donc, si l'entrée iterable est trié, les tuples de combinaison seront produits dans triés commande.
Les éléments sont traités comme uniques en fonction de leur position et non de leur évaluer. Donc, si les éléments d'entrée sont uniques, il n'y aura pas de répétition valeurs dans chaque combinaison.
C'est bien que vous fassiez référence à la documentation ... mais cela ne répond pas à la question.
Le isinstance ()
+ itertools.permutations ()
est une bonne direction, vous avez juste besoin d'un produit d'entre eux, et d'un suivi de quelle permutation s'applique à quelle partie de l'arbre (?) (je réfléchissais à la génération de tous les parcours possibles d'un arbre):
for r in swap([['a', ['b', 'c']], ['d'], 'e']): print(r) [['a', ['b', 'c']], ['d'], 'e'] [['a', ['c', 'b']], ['d'], 'e'] [[['b', 'c'], 'a'], ['d'], 'e'] [[['c', 'b'], 'a'], ['d'], 'e'] [['a', ['b', 'c']], 'e', ['d']] [['a', ['c', 'b']], 'e', ['d']] [[['b', 'c'], 'a'], 'e', ['d']] [[['c', 'b'], 'a'], 'e', ['d']] [['d'], ['a', ['b', 'c']], 'e'] [['d'], ['a', ['c', 'b']], 'e'] [['d'], [['b', 'c'], 'a'], 'e'] [['d'], [['c', 'b'], 'a'], 'e'] [['d'], 'e', ['a', ['b', 'c']]] [['d'], 'e', ['a', ['c', 'b']]] [['d'], 'e', [['b', 'c'], 'a']] [['d'], 'e', [['c', 'b'], 'a']] ['e', ['a', ['b', 'c']], ['d']] ['e', ['a', ['c', 'b']], ['d']] ['e', [['b', 'c'], 'a'], ['d']] ['e', [['c', 'b'], 'a'], ['d']] ['e', ['d'], ['a', ['b', 'c']]] ['e', ['d'], ['a', ['c', 'b']]] ['e', ['d'], [['b', 'c'], 'a']] ['e', ['d'], [['c', 'b'], 'a']]
plan ()
trouve récursivement toutes les "vraies" listes (qui ont plusieurs éléments), et crée itertools.permutations ()
pour eux.
swap ()
appelle plan () code >, puis combine les permutations en une seule mégapermutation composée en utilisant
itertools.product()
remix ()
crée un objet réel pour une seule mégapermutation étape. C'est un peu compliqué car je ne voulais pas me battre avec le suivi de la position de l'arborescence, à la place remix ()
fonctionne à l'envers, allant à la toute dernière liste, et la balançant avec le tout dernier composant du plan, en le supprimant de la liste.
Cela semble fonctionner, bien que votre exemple soit un peu long, avec des entrées plus simples, il a une sortie gérable:
import itertools def plan(part,res): if isinstance(part,list) and len(part)>1: res.append(itertools.permutations(range(len(part)))) for elem in part: plan(elem,res) return res def remix(part,p): if isinstance(part,list) and len(part)>1: coll=[0]*len(part) for i in range(len(part)-1,-1,-1): coll[i]=remix(part[i],p) mix=p.pop() return [coll[i] for i in mix] else: return part def swap(t): plans=itertools.product(*plan(t,[])) for p in plans: yield remix(t,list(p)) for r in swap([['a', 'b', 'c'], ['d'], ['e', 'f', ['g', ['h', 'i']]]]): print(r)
24 permutations, comme prévu