Функция Python для возврата списка списков только путем замены одних и тех же индексов

#python #list #combinations #permutation #itertools

#python #Список #комбинации #перестановка #itertools

Вопрос:

У меня есть два списка из 5 элементов. Я хочу использовать itertools, или код python возвращает список из 5 элементов, которые состоят из всех перестановок списка, только путем замены элементов двух списков с одинаковым индексом.

Например, если A = [1,2,3,4,5] и B = [a,b,c,d,e] , я хочу, чтобы он возвращал следующий список списков, C:

Случай, когда никакие элементы A не заменяются на B :

[1,2,3,4,5]

Случай, когда все индексы в A заменяются на B :

[a,b,c,d,e]

Случаи, когда только один элемент in A заменяется элементом in B с соответствующим индексом:

 [a, 2, 3, 4, 5]
[1, b, 3, 4, 5]
[1, 2, c, 4, 5]
[1, 2, 3, d, 5]
[1, 2, 3, 4, e]
 

Случаи, когда два элемента in A заменяются элементом in B с соответствующим индексом (ПРИМЕЧАНИЕ: это могут быть любые два элемента, два элемента не обязательно должны быть смежными):

[a, b, 3, 4, 5]

[1, b, c, 4, 5]

[1, 2, c, d, 5] … и т. д…

[a, 2, 3, 4, e]

[1, b, 3, c, 5] … и т. д…

Случаи, когда заменяются 3 элемента (опять же, это могут быть любые 3 элемента):

[a, b, c, 4, 5]

[1, b, c, d, 5] … и т. д…

Случаи, когда заменяются 4 элемента (любые 4 элемента):

[a, b, c, d, 5]

[a, 2, c, d, e]

[a, b, c, 4, e] …и т.д…

Я думал, что это будет просто с помощью itertools, но я столкнулся с проблемой при создании этого списка списков.

Комментарии:

1. Вы уверены, что имеете в виду здесь перестановки ? Потому что в ваших примерах порядок элементов списка никогда не меняется!

Ответ №1:

Вот один лайнер для этого:

 from itertools import product

A = [1,2,3,4,5]
B = ['a','b','c','d','e']
n = len(A)

out = [[(A if x[i] else B)[i] for i in range(n)] for x in product([0,1], repeat=n)]
 

или (немного) более pythonic:

 out = [[(A if y else B)[i] for i,y in enumerate(x)] for x in product([0,1], repeat=n)]
 

Объяснение:
x охватывает все возможности выбора i ‘-го элемента в любом A или B .

Если это слишком загадочно для вас, то вот расширенная версия:

 out = []
for x in product([0,1], repeat=n):
    l = []
    for i in range(n):
        if x[i]:
            l.append(A[i])
        else:
            l.append(B[i])
    out.append(l)
 

Комментарии:

1. Прохладный. Но однострочный, возможно, слишком dense для непосвященных …. (простой цикл for может помочь?)

2. Добавлена многострочная версия 🙂

3. Спасибо, ТИЛ. Лучше однострочный лайнер … 😉

Ответ №2:

Если я возьму ваши примеры и проигнорирую перестановки слов, то вам нужен итератор, который выполняет следующее: учитывая два списка одинаковой длины в качестве входных данных, он возвращает кучу списков, в которых элементы первого списка заменяются соответствующими элементами второго списка; и индексыэлементы, подлежащие замене, представляют собой все комбинации возможных индексов длиной N.

Вероятно, что-то либо с функцией генератора, либо с классом итератора…

 def get_list_replacement_combinations(list_a, list_b):
  # skipping some checks, like lists having same length
  N = len(list_a)
  for num_replaced_items in range(N 1):
    new_list = list(list_a) # make a copy so we don't mess up the original
    for combination in itertools.combinations(range(N), r=num_replaced_items):
      for index in combination:
        new_list[index] = list_b[index]
      yield new_list
 

Я придумал это на лету и не тестировал, поэтому могут быть ошибки, но это определенно общая идея. Вероятно, портит случай «длины 0» замененных элементов…