Python реверсирует некоторые части кортежа

1

Предположим, что у меня следующий кортеж:

a = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)

То, что я хочу сделать, - это обратить вспять некоторые части кортежа.

Например, 4 элемента остаются одинаковыми, а затем 4 элемента будут отменены.

Я хочу получить следующий результат:

a = (1,2,3,4,8,7,6,5,9,10,11,12,16,15,14,13,17,18,19,20) 

Как я могу достичь этого (как питонский вид)?

Спасибо...

  • 2
    Это не список, это кортеж ...
  • 0
    Вы не можете изменить кортеж, потому что кортежи неизменны. Вы можете создать новый кортеж, взяв кусочки исходного кортежа и комбинируя их. Использование ломтиков хорошо документировано.
Показать ещё 1 комментарий
Теги:
python-3.x
python-2.7

5 ответов

1
Лучший ответ

Однако кортежи неизменяемы, если преобразовать a в list, можно выполнить назначение на месте:

a = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
new_a = list(a)
for c, i in enumerate(range(0, len(a), 4)):
  if c%2: 
     new_a[i:i+4] = new_a[i:i+4][::-1]

print(tuple(new_a))

Выход:

(1, 2, 3, 4, 8, 7, 6, 5, 9, 10, 11, 12, 16, 15, 14, 13, 17, 18, 19, 20)
1

Вот решение на основе генератора. Преимущества этого способа заключаются в том, что это решение не требует, чтобы вход был разрезным, поэтому вы можете применить его к выводам таких функций, как zip и map.

from itertools import zip_longest as zipl
from itertools import cycle, chain

_marker = object()

def cycle_map(iterable, func_iterable):
    funcs = cycle(func_iterable)
    for func, item in zip(funcs, iterable):
        if func:
            yield func(item)
        else:
            yield item

def reverse_filter(iterable, remove=_marker):
    t = tuple(i for i in iterable if i is not remove)
    return reversed(t)

def reverse_alternating(iterable, length=4):
    chunks = zipl(*[iter(iterable)]*length, fillvalue=_marker)
    funcs = (None, reverse_filter) 
    return chain.from_iterable(cycle_map(chunks, funcs))

a = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
list(reverse_alternating(a))
# [1, 2, 3, 4, 8, 7, 6, 5, 9, 10, 11, 12, 16, 15, 14, 13, 17, 18, 19, 20]
1

Прямой, простой, читаемый ответ (pythonic?):

a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

for n in range(0, len(a), 8):
    a[n+4:n+8] = a[n+7:n+3:-1]

print(a)
0

Использование разрезания списков.

Пример:

from itertools import chain
a = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
res = [a[v:v+4] if i%2 == 0 else list(reversed(a[v:v+4])) for i, v in enumerate(range(0, len(a), 4))]
print(tuple(chain.from_iterable(res)))    #Flatten list

Выход:

(1, 2, 3, 4, 8, 7, 6, 5, 9, 10, 11, 12, 16, 15, 14, 13, 17, 18, 19, 20)
0

Еще один способ приблизиться к проблеме, используя понимание списка (не самый быстрый). Хотелось поделиться логикой, считая, что len(a) делится на 4:

a = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
lst = [a[j:j+4] if i%2 == 0 else a[j:j+4][::-1] for i, j in 
enumerate(range(0,len(a), 4))]
result = tuple([j for i in lst for j in i])
print (result)

Выход

(1, 2, 3, 4, 8, 7, 6, 5, 9, 10, 11, 12, 16, 15, 14, 13, 17, 18, 19, 20)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню