Reputation: 1415
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
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
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
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
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
n
is partialed into __getitem__()
of mit.circular_shifts()
f
composes the latter partial functionInstall this third-party library via > pip install more_itertools
.
Upvotes: 1
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
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