Операторы циклической перестановки в python - PullRequest
4 голосов
/ 16 мая 2019

Мне нужен функционал python (функция, которая создает функции), которая создает все операторы циклической перестановки для списка длины N.

Для списка Python (например, a = [1, 2, 3, 4,5,6], N= 6) можно определить функцию

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

, который дает вам все возможные циклические перестановки списка, в данном случае 6 списков.

Я бы хотел, чтобы функция давала мне не список, а (в данном случае) 6 операторов, каждый из которых при применении к списку дает один из перестановочных списков.

Ответы [ 4 ]

5 голосов
/ 16 мая 2019

Я не совсем уверен, какова цель этого упражнения, но вы можете сделать это с частичными функциями.

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]
3 голосов
/ 16 мая 2019

Вы можете написать функцию, которая возвращает функции:

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

Вывод:

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

Обратите внимание на wrapper(), который является способом захвата всех параметров, которые упакованная функцияcyc() нуждается в каждом экземпляре.

1 голос
/ 16 мая 2019

Вы можете сделать следующее.Вызов функции cyclic_perm для input_list вернет список операторов (функций), которые при вызове input_list дадут вам желаемый результат.

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 голосов
/ 17 мая 2019

Я интерпретирую ваш запрос как "при заданном количестве циклов n, реализую функцию, которая принимает n и возвращает функцию, которая при прохождении итерируемой возвращает итеративно смещенные n позиции."

Рассмотрим more_itertools.circular_shifts:

Дано

import functools as ft

import more_itertools as mit


iterable = range(6, 10)

Код

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

Демо

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)

Подробности

Наша composed_shifts() функция принимает целое число n shifts и

  1. возвращает функцию
  2. , которая при передаче итерируемого возвращает значение по индексу списка из mit.circular_shifts().Подробнее см. Ниже.

A круговой сдвиг - это особый тип циклической перестановки, показанный ниже:

mit.circular_shifts(iterable))

Выход

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

Как показано, возвращается список всех циклических сдвигов.Все, что нам нужно, это индекс для выбора определенного сдвига, n.Этот выбор выполняется с помощью __getitem__, который является частичным, чтобы задержать индексацию будущего списка.

Резюме

  • Сдвиг (индекс) n разделен на __getitem__() из mit.circular_shifts()
  • Внутренняя функция f составляет последняя частичная функция

Установите эту стороннюю библиотеку через > pip install more_itertools.

...