Умножьте каждый третий элемент списка на два - PullRequest
0 голосов
/ 30 мая 2019

Входные данные: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Выходные данные: [1, 2, 6, 4, 5, 12, 7, 8, 18, 10]

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

Можно ли улучшить мою реализацию?

for index in range(len(data)):
    if (index + 1) % 3 == 0:
        data[index] = data[index] * 2

Ответы [ 6 ]

9 голосов
/ 30 мая 2019

Да, вы можете сделать это с помощью обозначения среза:

data[2::3] = [x*2 for x in data[2::3]]

data[2::3] означает каждый третий элемент, начиная с индекса элемента 2 (то есть третьего элемента). Вы также можете переназначить обратно на фрагмент, учитывая этот очень лаконичный синтаксис.

3 голосов
/ 30 мая 2019

Ваше решение не так уж плохо. Его можно улучшить, просто перебирая нужные индексы напрямую, а не перебирая все индексы и пропуская ненужные:

for index in range(2, len(data), 3):
    data[index] *= 2

Это дает желаемый результат:

[1, 2, 6, 4, 5, 12, 7, 8, 18, 10]
3 голосов
/ 30 мая 2019

В итераторе range есть параметр "step":

for index in range(2, len(data), 3):
    data[index] *= 2

Это подойдет?

2 голосов
/ 30 мая 2019

Вы можете использовать цикл из itertools и zip для объединения элементов с их множителями:

data   = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

from itertools import cycle
result = [n*m for n,m in zip(data,cycle([1,1,2]))]

# [1, 2, 6, 4, 5, 12, 7, 8, 18, 10]

ИЛИ, вы можете использовать enumerate ()

result = [ n*max(1,i%3) for i,n in enumerate(data) ]
1 голос
/ 30 мая 2019

... и победитель:

Calculation time in seconds and results validation test.
1.150 question_by_akrapovich
0.331 answer_by_Tom_Karzes_and_Prune
0.333 answer_2_by_Manuel_Montoya
0.373 answer_by_Blorgbeard
0.816 answer_1_by_Alain_T
2.850 answer_2_by_Alain_T

Комбинированный код для проверки времени и проверки результатов:

import time


def question_by_akrapovich(data):
    for index in range(len(data)):
        if (index + 1) % 3 == 0:
            data[index] = data[index] * 2
    return data


def answer_by_Tom_Karzes_and_Prune(data):
    for index in range(2, len(data), 3):
        data[index] *= 2
    return data


def answer_by_Blorgbeard(data):
    data[2::3] = [x*2 for x in data[2::3]]
    return data


def answer_1_by_Alain_T(data):
    from itertools import cycle
    return [n * m for n, m in zip(data, cycle([1, 1, 2]))]


def answer_2_by_Alain_T(data):
    return [ n*max(1,i%3) for i,n in enumerate(data) ]


def answer_2_by_Manuel_Montoya(data):
    for index in range(2, len(data), 3):
        data[index] = data[index]*2
    return  data

def test(f):
    n = 10_000_000
    data = [i + 1 for i in range(n)]
    start_time = time.perf_counter()
    data = f(data)
    run_time = time.perf_counter() - start_time
    if n != len(data):
        print('error in list length', n, len(data))
        exit(1)
    for i in range(n):
        j = i + 1
        m = j * 2 if j % 3 == 0 else j
        if data[i] != m:
            print('error in data', i, m, data[i])
            exit(1)
    print('%.3f %s' % (run_time, f.__name__))


print('Calculation time in seconds and results validation test.')
for f in [question_by_akrapovich, answer_by_Tom_Karzes_and_Prune,
          answer_2_by_Manuel_Montoya, answer_by_Blorgbeard,
          answer_1_by_Alain_T, answer_2_by_Alain_T]:
    test(f)
1 голос
/ 30 мая 2019

Вы можете организовать это немного, передав третий аргумент в функцию range (), например:

for index in range(2, len(data), 3): data[index] = data[index]*2

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...