Есть ли способ накапливаться справа налево в Python?

#python #python-3.x #itertools #accumulate

Вопрос:

В Python уже есть itertools.accumulate функция. Однако эта функция накапливается слева направо:

 >>> list(itertools.accumulate([[x] for x in range(5)]))
[[0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4]]
 

Вместо этого я хотел бы накапливать справа налево, вот так:

 >>> list(accumulate_from_right([[x] for x in range(5)]))
[[0, 1, 2, 3, 4], [1, 2, 3, 4], [2, 3, 4], [3, 4], [4]]
 

Мое текущее решение (которое применимо только к спискам) очень неэффективно и уродливо:

 >>> list(x[::-1] for x in accumulate([y] for y in reversed(range(5))))[::-1]
[[0, 1, 2, 3, 4], [1, 2, 3, 4], [2, 3, 4], [3, 4], [4]]
 

Как лучше всего накапливать список справа налево?

Редактировать: Я использую диапазон только в качестве примера. Я хотел бы иметь возможность применять этот метод к любому вложенному списку.

Вот еще один пример, в котором не используется диапазон:

 >>> list(accumulate_from_right(['a', 'b', 'c']))
['abc', 'bc', 'c']
 

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

1. Это вопрос, accumulate в частности, или просто о том, как получить список «нисходящих» суффиксов?

2. print(list(itertools.accumulate([[x] for x in range(5, 0, -1)]))[::-1]) ?

3. Было бы полезно, если бы вы показали еще несколько примеров, чтобы стало ясно, каким образом вы хотите, чтобы это было обобщено.

4. @chepner Извини! Я неправильно понял, что вы имели в виду под «нисходящими» суффиксами. Я хочу, чтобы функция могла применять этот метод к любому списку!

Ответ №1:

Вам нужно всего лишь сделать один проход по входу accumulate_from_right :

 def accumulate_from_right(vals):
   return [vals[i:] for i in range(len(vals))]

print(accumulate_from_right(list(range(5))))
print(accumulate_from_right(['a', 'b', 'c']))
 

Выход:

 [[0, 1, 2, 3, 4], [1, 2, 3, 4], [2, 3, 4], [3, 4], [4]]
[['a', 'b', 'c'], ['b', 'c'], ['c']]
 

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

1. Это довольно умно, но есть ли способ обобщить этот метод? Я использовал диапазон только в качестве примера.

2. @PradhyumR, это должно хорошо обобщать — просто замените свой список на range(5) 🙂

3. Метод @Tim Ajax1234 использует сопоставление шаблонов и диапазон для создания желаемого результата. Это не будет хорошо обобщаться на строки (для чего я это и использую).

Ответ №2:

Вы могли бы попробовать что-то вроде

 [list(range(i, 5)) for i in range(5)]
 

ВОЗВРАТ

 [[0, 1, 2, 3, 4], [1, 2, 3, 4], [2, 3, 4], [3, 4], [4]]
 

Ответ №3:

Разве не легко использовать itertools, чтобы накапливать и использовать [::-1] в результате для обратного?

 list(itertools.accumulate([[x] for x in range(5)]))[::-1]
 

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

1. Нет, фактическое содержание списка будет другим