Периодически заменяя значения в списке
Предположим, у меня есть следующий список в Python:
my_list = [10] * 95
Учитывая n
, я хочу заменить любые другие m
элементы на нуль в моем списке, сохраняя следующие n
элементов.
Например, если n = 3
и m = 2
, я хочу, чтобы мой список выглядел так:
[10, 10, 10, 0, 0, 10, 10, 10 ,0, 0, ..., 10, 10, 10 , 0, 0]
Если он не может быть заполнен отлично, как в случае с n = 4
и m = 2
, тогда это ОК, если мой список выглядит следующим образом:
[10, 10, 10, 10, 0, 0, ..., 10, 10, 10, 10, 0]
Как я должен попытаться решить эту проблему?
Ответы
Ответ 1
my_list = [10] * 95
n = 3
m = 2
for i in range(m):
my_list[n+i::m+n] = [0] * len(my_list[n+i::m+n])
Для этого требуется только m
заданий для выполнения задания (и m
вероятно, мало).
Если у вас действительно есть только два возможных значения (например, 10 и 0), вы можете сделать это еще проще:
my_list = [ 10 if i % (n+m) < n else 0 for i in range(95) ]
Но это повторяется в Python во всем диапазоне 95, поэтому, вероятно, это не очень быстро.
Немного более сложный, но, вероятно, более эффективный (особенно для огромных списков и больших значений для n
и m
):
my_list = (([ 10 ] * n + [ 0 ] * m) * (95 // (n + m) + 1))[:95]
Но он строит внутри множество списков, поэтому до тестов нужно выяснить, насколько это эффективно в вашем случае. (Также необходимо учитывать потребление памяти для больших списков.)
Если вы можете использовать numpy
(немного от вопроса, но с его распространением):
my_list = (np.arange(95) % (n+m) < n) * 10
Ответ 2
Вы можете использовать itertools.cycle
для создания бесконечной последовательности [10, 10, 10, 0, 0]
а затем взять первые 95 элементов этой последовательности с помощью itertools.islice
:
n = 3
m = 2
pattern = [10] * n + [0] * m
my_list = list(itertools.islice(itertools.cycle(pattern), 95))
Ответ 3
Еще одна возможность, на этот раз с enumerate
:
[x * (i % (n + m) < n) for i, x in enumerate(my_list)]
Он использует тот факт, что False
и True
равны 0
и 1
в Python (см. Здесь).
В качестве бонуса он отлично работает, даже если список не является постоянным:
>>> n = 4
>>> m = 2
>>> my_list = range(20)
>>> [x * (i % (n+m) < n) for i, x in enumerate(my_list)]
[0, 1, 2, 3, 0, 0, 6, 7, 8, 9, 0, 0, 12, 13, 14, 15, 0, 0, 18, 19]
Если список содержит строки, он заменяет их пустой строкой вместо 0
:
>>> my_list = 'abcdefghijk'
>>> [x * (i % (n+m) < n) for i, x in enumerate(my_list)]
['a', 'b', 'c', 'd', '', '', 'g', 'h', 'i', 'j', '']
Ответ 4
Это сработало для меня:
list = [10] * 95
n = 4
m = 2
amask = np.tile(np.concatenate((np.ones(n),np.zeros(m))),int((len(list)+1)/(n+m)))[:len(list)]
list = np.asarray(list)*amask
который выводит:
array([10., 10., 10., 10., 0., 0., 10., 10., 10., 10., 0., 0., 10.,
10., 10., 10., 0., 0., 10., 10., 10., 10., 0., 0., 10., 10.,
10., 10., 0., 0., 10., 10., 10., 10., 0., 0., 10., 10., 10.,
10., 0., 0., 10., 10., 10., 10., 0., 0., 10., 10., 10., 10.,
0., 0., 10., 10., 10., 10., 0., 0., 10., 10., 10., 10., 0.,
0., 10., 10., 10., 10., 0., 0., 10., 10., 10., 10., 0., 0.,
10., 10., 10., 10., 0., 0., 10., 10., 10., 10., 0., 0., 10.,
10., 10., 10., 0.])
Код принимает n
и m
и создает маску единиц и нулей с длиной, соответствующей вашему первоначальному list
с np.tile
функции np.tile
. После этого вы просто умножаете маску на список и получаете нули, где вы хотите, чтобы они были. Он также должен быть flexibel для разных длин списка и (почти) произвольного выбора n
и m
.
Если хотите, вы можете вернуть массив в список.
Ответ 5
Как насчет этого?
my_list = [10] * 95
n = 3
m = 2
for i in range(n, len(my_list)-1, n+m):
my_list[i:i+m] = [0]*m
print(my_list)
редактировать
Я узнал, что приведенный выше код в некоторых случаях изменяет длину результирующего списка.
>>> a = [1,2,3]
>>> a[2:4] = [0] * 2
>>> a
[1, 2, 0, 0]
Таким образом, длина должна каким-то образом восстановиться.
my_list = [10] * 95
cp_list = list(my_list)
n = 3
m = 5
for i in range(n, len(my_list)-1, n+m):
cp_list[i:i+m] = [0]*m
cp_list = cp_list[:len(my_list)]
print(cp_list)
Ответ 6
[j for i in [[input_num] * n + [0] * m for x in range(int(num / (m + n)) + 1)][:num] for j in i]
Может быть?
Результат
>>> num, input_num, m, n=95, 10, 2, 3
>>> [j for i in [[input_num] * n + [0] * m for x in range(int(num / (m + n)) + 1)][:num] for j in i]
[10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0, 10, 10, 10, 0 , 0, 10, 10, 10, 0, 0, 10, 10, 10, 0, 0]
Ответ 7
numpy
может сделать это довольно сжато, слишком!
a = np.array(my_list).reshape(-1, n + m)
a[:, n:] = 0
result = a.ravel().tolist()
Ответ 8
Также в семье itertools вы можете repeat
желаемый шаблон:
Дано
import itertools as it
m, n = 2, 3
p = n + 1
Код
pattern = it.repeat([10] * n + [0] * m)
res = list(it.islice(it.chain.from_iterable(pattern), None, 95))
print(res)
# [10, 10, 10, 10, 0, 0, 10, 10, 10, 10, 0, 0, ... 10, 10, 10, 10, 0, 0]
pattern = it.repeat([10] * p + [0] * m)
res = list(it.islice(it.chain.from_iterable(pattern), None, 95))
print(res)
# [10, 10, 10, 10, 0, 0, 10, 10, 10, 10, 0, 0, ... 10, 10, 10, 10, 0]
Тестовое задание
assert len(res) == 95
Однако решение @Aran-Fey itertools.cycle
является более чистым, поскольку оно не требует цепочки.