1
votes

Comment obtenir toutes les permutations possibles?

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?


0 commentaires

3 Réponses :


1
votes

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]]


2 commentaires

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



0
votes

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.


1 commentaires

C'est bien que vous fassiez référence à la documentation ... mais cela ne répond pas à la question.



2
votes

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


0 commentaires