#python #for-loop #range
Вопрос:
У меня есть строка string = 'cbAfeDihGlkJonMrqPutS'
, и я хотел бы выполнить итерацию по ней, чтобы получить 'AbcDefGhiJklMnoPqrStu'
результат.
Я использую следующий цикл for для достижения 'DefGhiJklMnoPqrStu
, однако ожидаемое Abc
отсутствует.
for i in (range(0, len(string), 3)):
print(string[i 2 : i-1 : -1], end='')
Кажется, это проблема из-за -1
в моем конечном элементе : i-1 :
, однако мне интересно, почему повторение в обратном порядке (с размером шага -1
) и использование :i-1:
для захвата первого элемента (где i = 0) не работает аналогично итерации вперед и использованию : i 1 :
для захвата последнего элемента.
Я могу достичь желаемого решения с помощью
for i in (range(0, len(string), 3)):
print(string[i:i 3:1][::-1], end='')
но итерация вперед и печать назад кажется неуклюжим способом сделать это. Необходимость добавления [::-1]
кажется излишним шагом, который [i 2 : i-1 : -1]
должен был сработать.
Есть ли более чистый способ сделать это, кроме [i:i 3:1][::-1]
?
Комментарии:
1.
''.join(sorted(list(string), key=str.lower))
2. «.join(sorted(string , key=str.casefold)) должен дать желаемый результат.
Ответ №1:
Вероятно, самый элегантный способ сделать это — использовать ''.join()
и понимание, чтобы сжать цикл, который вы уже придумали, в одну строку.
string = 'cbAfeDihGlkJonMrqPutS'
print(''.join(string[i:i 3][::-1] for i in range(0, len(string), 3)))
# AbcDefGhiJklMnoPqrStu
Можно подумать, что вы сможете избавиться от лишнего [::-1]
, выполнив like string[i 2:i-1:-1]
, но, как вы заметили, это отсекает первый символ в строке. Это особенность синтаксиса среза: end
граница среза является исключающей, а не включающей, но в то же время индекс ссылается на конец строки, а не на «символ перед началом» (что было бы за пределами, скажем, в Java, но в котором мы бы не сталиу меня нет -1
этой проблемы). Насколько мне известно, обойти это невозможно.
Вы также можете попробовать использовать reversed()
вместо [::-1]
, но я не думаю, что это делает его проще или быстрее:
print(''.join(c for i in range(0, len(string), 3) for c in reversed(string[i:i 3])))
РЕДАКТИРОВАТЬ: поскольку @don’t talk just code указано в комментарии, на самом деле проблему можно обойти, поскольку включение None
в качестве второго аргумента фрагмента приведет к переходу фрагмента в любой конец списка, который подходит (до этого комментария я этого не знал). Имея это в виду, мы действительно можем сделать это только в одном фрагменте:
print(''.join(string[i 2:i-1 if i else None:-1] for i in range(0, len(string), 3)))
# AbcDefGhiJklMnoPqrStu
Это немного неэлегантно, но, похоже, работает, и было бы больше того, что вы ищете, чем указано выше.
Комментарии:
1. Я, конечно, рассмотрю ваше подтверждение того, что «нет никакого способа обойти это» в качестве удовлетворительного ответа. Облом, что этот случай попадает через трещины интуитивного нарезания. Спасибо
2. @ZwiTrader Вы могли бы сделать
i-1 if i else None
вместоi-1
. Или сохранитьi-1
, но удвоить отрицательные значения, используяrange(-len(string), 0, 3)
.3. @don’tt tal justcode, ПОКА это не произойдет. Я соответствующим образом отредактировал свой ответ, спасибо, что напомнили об этом
4. Да,
None
это просто значение по умолчанию, эквивалентное пропуску значения ( демонстрация ). Вы также пробовали отрицательный диапазон? Это необычно, но также просто и, возможно, немного быстрее.5. Спасибо за оба предложения @ не говорите только о коде. Об этом интересно узнать
i-1 if i else None
как о опции, но «удвоение негативов», как вы говорите, компактно и соответствует тому, что я искал в первую очередь. Идеальный.