Мы можем покончить с вопросами 2 и 3, ответив на вопрос 1, но понимание вопроса 3 важно, поэтому сначала я сделаю это, а затем покажу, как можно полностью избежать этого:
Вопрос 3
Что касается вопроса 3, то это потому, что когда вы перебираете список в python и вносите в него изменения в цикле , список, над которым вы зацикливаетесь, меняется.
Из документов python о потоке управления (для секции операторов) :
небезопасно изменять последовательность, повторяемую в цикле
(это может происходить только для типов изменяемых последовательностей, таких как списки).
Скажите, что ваш список [a,b,c,d]
, и вы просматриваете его с помощью for el in List
.
Скажите el
в настоящее время a
, а вы List.remove(el)
.
Теперь ваш список [b,c,d]
. Тем не менее, итератор указывает на второй элемент в списке (так как он сделал первый), который теперь c
.
По сути, вы пропустили b
. Так что проблема в том, что вы модифицируете список, по которому вы перебираете.
Есть несколько способов исправить это: если ваш List
не является дорогостоящим для копирования, вы можете сделать копию. Так итерируйте по List[:]
, но удалите из List
.
Но предположим, что постоянно делать копии List
дорого.
Тогда вы делаете итерацию по ней назад . Обратите внимание на reversed
ниже:
for el in reversed(List):
if el.count('$') < n:
counter+=1
List.remove(el)
return(List)
В приведенном выше примере предположим, что мы повторяем в обратном направлении по List
.
Итератор начинается с d
, а затем переходит к c
.
Предположим, мы удалили c
, так что List=[a,b,d]
.
Поскольку итератор движется назад , теперь он указывает на элемент b
, поэтому мы ничего не пропустили.
По сути, это позволяет избежать изменения битов списка, который вам еще предстоит перебрать.
Вопросы 1 и 2
Если я правильно понимаю ваш вопрос, вы, в основном, хотите выбрать n
из m
позиций, где m
- длина строки (abcde
), и поставить '$' в каждом из эти n
позиции.
В этом случае вы можете использовать для этого модуль itertools
.
import itertools
def Mismatch(Search,n):
SearchL = list(Search)
List = [] # hold output
# print list of indices to replace with '$'
idxs = itertools.combinations(range(len(SearchL)),n)
# for each combination `idx` in idxs, replace str[idx] with '$':
for idx in idxs:
str = SearchL[:] # make a copy
for i in idx:
str[i]='$'
List.append( ''.join(str) ) # convert back to string
return List
Давайте посмотрим, как это работает:
- превратить строку
Search
в список, чтобы ее можно было перебрать, создать пустое List
для хранения результатов.
idxs = itertools.combinations(range(len(SearchL)),n)
говорит "найти все подмножества длины n в наборе [0,1,2,3,...,length-of-search-string -1]
.
Попробуйте
idxs = itertools.combinations(range(5),4)
for idx in idxs:
print idx
чтобы понять, что я имею в виду.
- Каждый элемент
idxs
является кортежем n
индексов от 0 до len(SearchL)-1
(например, (0,1,2,4)
. Замените i-й символ SearchL
на '$' для каждого i
в кортеж.
- Преобразовать результат обратно в строку и добавить его к
List
.
Как пример:
Mismatch('abcde',3)
['$$$de', '$$c$e', '$$cd$', '$b$$e', '$b$d$', '$bc$$', 'a$$$e', 'a$$d$', 'a$c$$', 'ab$$$']
Mismatch('abcde',4) # note, the code you had made lots of duplicates.
['$$$$e', '$$$d$', '$$c$$', '$b$$$', 'a$$$$']