Uwe.Schneider
Uwe.Schneider

Reputation: 1415

Cyclic permutation operators in python

I need a python functional (a function that creates functions), which creates all cyclic permutation operators for a list of length N.

For a python list a (e.g. a = [1, 2, 3, 4,5,6], N= 6), one can define a function

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

that gives you all the possible, cyclic permutations of a list, in this case 6 lists.

I would like the function to give me not the list, but (in this case) 6 operators, that ,when applied to the list, each give one of the permuted lists.

Upvotes: 7

Views: 9052

Answers (5)

user3124688
user3124688

Reputation: 11

Perhaps this is too slow, but why not just use mod? E.g.

def cycle(colors,n):
   return [colors[(n + i) % len(colors)] for i in range(len(colors))]

Then you could get your list of permutations with:

[cycle(colors,j) for j in range(len(colors))]

Upvotes: 1

Paritosh Singh
Paritosh Singh

Reputation: 6246

I am not too sure what the goal of this exercise is, but you can do this with partial functions.

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]

Upvotes: 5

pylang
pylang

Reputation: 44525

I interpret your request as "given a number of cycles n, implement a function that accepts n and returns a function that when passed an iterable, returns the iterable shifted n positions."

Consider more_itertools.circular_shifts:

Given

import functools as ft

import more_itertools as mit


iterable = range(6, 10)

Code

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

Demo

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)

Details

Our composed_shifts() function accepts an integer of n shifts and

  1. returns a function
  2. that when passed an iterable, returns the value at the index of the list from mit.circular_shifts(). See more details below.

A circular shift is a specific type of cyclic permutation, demonstrated below:

mit.circular_shifts(iterable))

Output

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

As shown, a list of all circular shifts is returned. All we need is an index to select a specific shift, n. This selection is accomplished by __getitem__, which is partialed to delay indexing the future list.

Summary

  • The shift (index) n is partialed into __getitem__() of mit.circular_shifts()
  • The inner function f composes the latter partial function

Install this third-party library via > pip install more_itertools.

Upvotes: 1

Praveenkumar
Praveenkumar

Reputation: 2182

You can do the following. Calling cyclic_perm function on a input_list will return list of operators (functions) that when called on the input_list will give you the desired result.

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

Upvotes: 1

quamrana
quamrana

Reputation: 39374

You can write a function which returns functions:

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

Output:

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

Note the wrapper() which is the way of capturing all the parameters which the wrapped function cyc() needs in each instance.

Upvotes: 4

Related Questions