9
votes

Générer des changements circulaires / des carrés latins réduits en python

se demandait simplement quelle est la manière la plus efficace de générer tous les changements circulaires d'une liste en python. Dans les deux sens. Par exemple, étant donné une liste [1, 2, 3, 4] , je veux générer: xxx

où la prochaine permutation est générée en déplaçant le dernier élément à l'avant, ou: xxx

où la prochaine permutation est générée en déplaçant le premier élément à l'arrière.

Le second cas est légèrement plus Intéressant pour moi, car il entraîne une place latine réduite (le premier cas donne également un carré latin, tout simplement pas réduit), ce que j'essaie d'utiliser pour faire la conception de bloc expérimentale. En réalité, ce n'est pas si différent du premier cas, car ils ne sont que des réchrographies les uns des autres, mais l'ordre est toujours important.

La mise en œuvre actuelle que j'ai pour le premier cas est la suivante: xxx

pour le second cas: xxx

Le premier cas semble être raisonnablement efficace pour moi, car il utilise < CODE> POP () , mais vous ne pouvez pas faire cela dans le second cas, j'aimerais donc entendre des idées sur la manière de le faire plus efficacement. Peut-être qu'il y a quelque chose dans itTools qui aidera? Ou peut-être une file d'attente à double extrémité pour le second cas?


2 commentaires

Votre implémentation ne fonctionne pas - ils ajoutent une liste (INTS) et des listes, ce qui est impossible. En outre, ils sont ajoutés à la même instance de liste dans chaque itération. Vous allez donc vous retrouver avec un carré composé de N fois la même ligne.


Whoops, a raté cela, merci. N'a pas réellement testé le code: p


7 Réponses :


11
votes

Pour la première partie, la manière la plus concise est probablement xxx

et pour la deuxième partie xxx

celles-ci devraient également être beaucoup plus efficace que votre code, bien que je n'ai pas fait de timings.


1 commentaires

Wow, ne pensais pas que vous pourriez faire cela en utilisant des compréhensions de la liste! J'aurais peut-être dû penser plus fort. Les accessoires de ne pas avoir à utiliser de modules supplémentaires.



18
votes

Vous pouvez utiliser collections.deque: xxx

IT imprime: xxx

pour le changer pour la rotation gauche, remplacez simplement g.rotate (1) avec g.rotate (-1) .


3 commentaires

Cette méthode rotation est assez cool. Je ne savais jamais que desquelles pouvaient faire ça. Là encore, j'ai probablement lu la documentation à fond avant de demander.


Comme il s'agit de la file d'attente double extrémité, rotation est probablement implémenté efficacement.


Et les documentations sont en effet nos meilleurs amis. :)



-1
votes

Utilisation d'iTerTools pour éviter l'indexation:

x = itertools.cycle(a)
[[x.next() for i in a] for j in a]


0 commentaires

-1
votes

Ce sera ma solution.

[4, 1, 2, 3]
[3, 4, 1, 2]
[2, 3, 4, 1]
[1, 2, 3, 4]


0 commentaires

6
votes

Variation de la "Droit de la conservation" A = A [: I] + A [I:] CODE>

ns = list(range(5))
ns
Out[34]: [0, 1, 2, 3, 4]

[ns[i:] + ns[:i] for i in range(len(ns))]
Out[36]: 
[[0, 1, 2, 3, 4],
 [1, 2, 3, 4, 0],
 [2, 3, 4, 0, 1],
 [3, 4, 0, 1, 2],
 [4, 0, 1, 2, 3]]


[ns[-i:] + ns[:-i] for i in range(len(ns))]
Out[38]: 
[[0, 1, 2, 3, 4],
 [4, 0, 1, 2, 3],
 [3, 4, 0, 1, 2],
 [2, 3, 4, 0, 1],
 [1, 2, 3, 4, 0]]


0 commentaires

0
votes

La réponse de @bruno Lenzi ne semble pas fonctionner: xxx pré>

i Donnez une version correcte ci-dessous, mais la solution de @ F5R5E5D est plus rapide. P>

In [45]: def use_cycle(a):
    x=cycle(a)
    for _ in a:
        x.next()
        print [x.next() for _ in a]
   ....:         

In [46]: use_cycle([1,2,3,4])
[2, 3, 4, 1]
[3, 4, 1, 2]
[4, 1, 2, 3]
[1, 2, 3, 4]

In [50]: def use_slice(a):
    print [ a[n:] + a[:n] for n in range(len(a)) ]
  ....:     

In [51]: use_slice([1,2,3,4])
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]

In [54]: timeit.timeit('use_cycle([1,2,3,4])','from __main__ import use_cycle',number=100000)
Out[54]: 0.4884989261627197

In [55]: timeit.timeit('use_slice([1,2,3,4])','from __main__ import use_slice',number=100000)
Out[55]: 0.3103291988372803

In [58]: timeit.timeit('use_cycle([1,2,3,4]*100)','from __main__ import use_cycle',number=100)
Out[58]: 2.4427831172943115

In [59]: timeit.timeit('use_slice([1,2,3,4]*100)','from __main__ import use_slice',number=100)
Out[59]: 0.12029695510864258


0 commentaires

1
votes

more_itertools code> est une bibliothèque tierce qui offre un outil pour Permutations cycliques :

import more_itertools as mit


mit.circular_shifts(range(1, 5))
# [(1, 2, 3, 4), (2, 3, 4, 1), (3, 4, 1, 2), (4, 1, 2, 3)]


0 commentaires