Periodically replacing values in a list

Suppose I have the following list in Python:

my_list = [10] * 95


Given n, I want to replace any other m elements with zero in my list, while keeping the next n elements.

For example, if n = 3 and m = 2, I want my list to look like:

[10, 10, 10, 0, 0, 10, 10, 10 ,0, 0, ..., 10, 10, 10 , 0, 0]


If it can't be filled perfectly, as is the case with n = 4 and m = 2, then it's OK if my list looks like this:

[10, 10, 10, 10, 0, 0, ..., 10, 10, 10, 10, 0]


How should I try to solve this problem?

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])


This just needs m assignments to do the job (and m probably is small).

If you really just have two possible values (e. g. 10 and 0), you can do it even simpler:

my_list = [ 10 if i % (n+m) < n else 0 for i in range(95) ]


But that iterates in Python over the whole range of 95, so probably is not very fast.

A bit more complex but probably more efficient (especially for huge lists and large values for n and m) would be this:

my_list = (([ 10 ] * n + [ 0 ] * m) * (95 // (n + m) + 1))[:95]


But it builds internally lots of lists, so its up to tests to find out whether this is efficient in your case. (Also memory consumption should be taken into account for large lists.)

If you can use numpy (a bit off the question, but since it's widespread):

my_list = (np.arange(95) % (n+m) < n) * 10


You could use itertools.cycle to create an endless sequence of [10, 10, 10, 0, 0] and then take the first 95 elements of that sequence with itertools.islice:

n = 3
m = 2

pattern = [10] * n + [0] * m
my_list = list(itertools.islice(itertools.cycle(pattern), 95))


This worked for me:

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


which outputs:

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.])


The code takes n and m and constructs a mask of ones and zeros with a length matching your initial list using the np.tile function. Afterwards you just multiply the mask onto the list and get the zeros where you want them to be. It should also be flexibel to different lengths of the list and an (almost) arbitrary choice of n and m.

You can cast the array back to a list if you want.

numpy can do this pretty concisely, too!

a = np.array(my_list).reshape(-1, n + m)
a[:, n:] = 0
result = a.ravel().tolist()


How about this?

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)




Edit

I found out that the above code changes the length of resulting list in some cases.

>>> a = [1,2,3]
>>> a[2:4] = [0] * 2
>>> a
[1, 2, 0, 0]


Thus, the length should be restored somehow.

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)


Yet another possibility, this time with enumerate:

[x * (i % (n + m) < n) for i, x in enumerate(my_list)]


It uses the fact that False and True are equal to 0 and 1 in Python (see here).

As a bonus, it works fine even if the list isn't constant:

>>> 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]


If the list contains strings, it replaces them with an empty string instead of 0:

>>> my_list = 'abcdefghijk'
>>> [x * (i % (n+m) < n) for i, x in enumerate(my_list)]
['a', 'b', 'c', 'd', '', '', 'g', 'h', 'i', 'j', '']


[j for i in [[input_num] * n + [0] * m for x in range(int(num / (m + n)) + 1)][:num] for j in i]


Maybe?

Result

>>> 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]

Comments

Popular posts from this blog

Meaning of `{}` for return expression

Get current scroll position of ScrollView in React Native

React Native - Image Cache