3
votes

Opérateurs de permutation cyclique en python

J'ai besoin d'une fonctionnelle python (une fonction qui crée des fonctions), qui crée tous les opérateurs de permutation cyclique pour une liste de longueur N.

Pour une liste python a (par exemple a = [1, 2, 3 , 4,5,6], N = 6 ), on peut définir une fonction

def cyclic_perm(a):
    n = len(a)
    b = [[a[i - j] for i in range(n)] for j in range(n)]
    return b

qui vous donne toutes les permutations cycliques possibles d'une liste, dans ce cas, 6 listes.

Je voudrais que la fonction ne me donne pas la liste, mais (dans ce cas) 6 opérateurs, qui, lorsqu'ils sont appliqués à la liste, donnent chacun une des listes permutées.

p>


8 commentaires

Je ne sais pas ce que signifie la dernière phrase. Pourriez-vous fournir un exemple?


Veuillez mettre à jour votre question avec un exemple d'utilisation qui suppose que vous avez déjà votre fonction qui crée des fonctions.


Vous voudrez peut-être aussi simplement stocker les options dans un dictionnaire. Mais veuillez fournir une sortie souhaitée.


En passant, il vaut probablement mieux utiliser itertools.permutations que de réinventer la roue


Vous l'avez déjà là lambda a, j: [a [i - j] for i in range (len (a))] . Il s'agit d'une fonction qui donne une liste et un décalage renvoie une liste pivotée.


Les rotations @DeepSpace ne sont pas des permutations. Ils sont un sous-ensemble qui maintient le cyclique adjacent.


@DanD. assez juste, mais je suis sûr qu'il existe une recette itertools qui ne nous fera pas (ou l'OP) réinventer la roue :) (non pas que ce soit si complexe dans ce cas ...)


La définition habituelle de la "permutation cyclique" est un concept complètement différent de ce que vous demandez .


4 Réponses :


3
votes

Vous pouvez écrire une fonction qui renvoie des fonctions:

[[1, 2, 3, 4, 5, 6], [6, 1, 2, 3, 4, 5], [5, 6, 1, 2, 3, 4], [4, 5, 6, 1, 2, 3], [3, 4, 5, 6, 1, 2], [2, 3, 4, 5, 6, 1]]
[[1, 2, 3, 4, 5, 6], [6, 1, 2, 3, 4, 5], [5, 6, 1, 2, 3, 4], [4, 5, 6, 1, 2, 3], [3, 4, 5, 6, 1, 2], [2, 3, 4, 5, 6, 1]]

Sortie:

def cyclic_perm(a):
    n = len(a)
    b = [[a[i - j] for i in range(n)] for j in range(n)]
    return b

def cyclic_perm_func(a):
    n = len(a)
    def wrapper(a, n, j):
        def cyc():
            return [a[i - j] for i in range(n)]
        return cyc
    b = [wrapper(a, n, j) for j in range(n)]
    return b

a = [1, 2, 3, 4,5,6]
print(cyclic_perm(a))  # Your original function
f = cyclic_perm_func(a) # f is now a list of functions
print([g() for g in f])  # Let's call each in turn

Notez le wrapper () code> qui est le moyen de capturer tous les paramètres dont la fonction encapsulée cyc () a besoin dans chaque instance.


0 commentaires

5
votes

Je ne sais pas trop quel est l'objectif de cet exercice, mais vous pouvez le faire avec des fonctions partielles.

from functools import partial

def reorder_from_idx(idx, a):
    return a[idx:] + a[:idx]

def cyclic_perm(a):
    return [partial(reorder_from_idx, i) for i in range(len(a))]


a = [1, 2, 3, 4, 5, 6]
result = cyclic_perm(a)
print(result)
#[functools.partial(<function reorder_from_idx at 0x00000298D92189D8>, 0),
# functools.partial(<function reorder_from_idx at 0x00000298D92189D8>, 1),
# functools.partial(<function reorder_from_idx at 0x00000298D92189D8>, 2),
# functools.partial(<function reorder_from_idx at 0x00000298D92189D8>, 3),
# functools.partial(<function reorder_from_idx at 0x00000298D92189D8>, 4),
# functools.partial(<function reorder_from_idx at 0x00000298D92189D8>, 5)]
result[3](a)
#[4, 5, 6, 1, 2, 3]


1 commentaires

Bel exemple de fonctions partielles @ParitoshSingh +1 Je suppose que j'ai besoin d'en savoir plus à leur sujet!



1
votes

Vous pouvez faire ce qui suit. L'appel de la fonction cyclic_perm sur une input_list renverra une liste d'opérateurs (fonctions) qui, lorsqu'ils sont appelés sur input_list, vous donneront le résultat souhaité.

input_list = [1, 2, 3, 4, 5, 6]


def cyclic_perm(a):
    n = len(a)
    result = []
    for j in range(n):
        def f(l, k=j):
            return list(map(lambda i: l[i - k], range(n)))
        result.append(f)
    return result


for op in cyclic_perm(input_list):
    print(op(input_list))


0 commentaires

1
votes

J'interprète votre requête comme "étant donné un nombre de cycles n , j'implémente une fonction qui accepte n et renvoie une fonction qui, lorsqu'elle est passée à un itérable, renvoie les positions n décalées itérables. "

Considérez more_itertools.circular_shifts :

Donné

[(6, 7, 8, 9),                                             # 0 shifts
 (7, 8, 9, 6),                                             # 1   " 
 (8, 9, 6, 7),                                             # 2   " 
 (9, 6, 7, 8)]                                             # 3   "

Code

mit.circular_shifts(iterable))

Démo^

composed_shifts(1)                                         # 1
# <function __main__.composed_shifts.<locals>.f(x)>

composed_shifts(1)(iterable)                               # 2
# (7, 8, 9, 6)

composed_shifts(3)(iterable)
# (9, 6, 7, 8)

Détails

Notre fonction compose_shifts () accepte un entier de n décalages et

  1. renvoie une fonction
  2. que lorsqu'il est passé un itérable, renvoie la valeur à l'index de la liste à partir de mit.circular_shifts () . Voir plus de détails ci-dessous.

Un décalage circulaire est un type spécifique de permutation cyclique, illustré ci-dessous :

def composed_shifts(n):
    """Return a function of `n` circular shifts."""
    def f(x):    
        return ft.partial(mit.circular_shifts(x).__getitem__, n)()
    return f

Sortie

import functools as ft

import more_itertools as mit


iterable = range(6, 10)

Comme indiqué, une liste de tous les décalages circulaires est renvoyée. Tout ce dont nous avons besoin est un index pour sélectionner une équipe spécifique, n . Cette sélection est accomplie par __getitem__ , qui est partiel pour retarder l'indexation de la future liste.

Résumé

  • Le décalage (index) n est partiel en __getitem __ () de mit.circular_shifts()
  • La fonction interne f compose cette dernière fonction partielle

Installez cette bibliothèque tierce via > pip install more_itertools .


0 commentaires