Edit the value of every Nth item in a list - python

What's the most pythonic way of performing an arithmetic operation on every nth value in a list? For example, if I start with list1:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I would like to add 1 to every second item, which would give:
list2 = [1, 3, 3, 5, 5, 7, 7, 9, 9, 11]
I've tried:
list1[::2]+1
and also:
for x in list1:
x=2
list2 = list1[::x] + 1

You could use slicing with a list comprehension as follows:
In [26]: list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [27]: list1[1::2] = [x+1 for x in list1[1::2]]
In [28]: list1
Out[28]: [1, 3, 3, 5, 5, 7, 7, 9, 9, 11]

numpy allows you to use += operation with slices too:
In [15]: import numpy as np
In [16]: l = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
In [17]: l[1::2] += 1
In [18]: l
Out[18]: array([ 1, 3, 3, 5, 5, 7, 7, 9, 9, 11])

Use enumerate and a list comprehension
>>> list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> [v+1 if i%2!=0 else v for i,v in enumerate(list1)]
[1, 3, 3, 5, 5, 7, 7, 9, 9, 11]

list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in range(1, len(list1), 2):
list1[i] +=1
print(list1)
using i%2 seems not very efficient

Try this:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in range(1,len(list1),2):
list1[i] += 1

You can create an iterator representing the delta (itertools.cycle([0, 1]) and then add its elements to your existing list.
>>> list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> [a + b for a,b in zip(list1, itertools.cycle([0,1]))]
[1, 3, 3, 5, 5, 7, 7, 9, 9, 11]
>>>

a = [i for i in range(1,11)]
#a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [a[i]+1 if i%2==1 else a[i] for i in range(len(a))]
#b = [1, 3, 3, 5, 5, 7, 7, 9, 9, 11]

Related

How to repeat the numbers in a list in python?

I have a list
A = [1,6,3,8,5,5,2,1,2,10]
I want to repeat the numbers in this like:
A = [1,6,6,6,6,6,6,3,3,3,8,8,8,8,8,8,8,8,..... so on]
i.e 1 repeat once, 6 repeat six times, 3 repeat thrice and so on....
I tried with:
B=np.concatenate([([x]*x) for x in A], axis=0)
but it multiplying the corresponding number and I am getting this result:
B = [1,36,36,36,36,36,36,9,9,9,.....so on]
when I am doing:
B=np.concatenate([([x]*3) for x in A], axis=0)
this giving me:
B = [1,1,6,6,3,3,8,8... so on]
what wrong I am doing here?
You can perform this operation using numpy without using a for loop.
np.repeat(a, repeats) will repeat the input array a according to repeats which specify the number of repetitions for each element.
import numpy as np
A = [1,6,3,8,5,5,2,1,2,10]
B = np.repeat(A,A)
Output:
>>> array([ 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 8, 8, 8, 8, 8, 8, 8,
8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 1, 2, 2, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10])
Using the repeat function of NumPy you can get the solution
import numpy as np
np.repeat(A, A)
You should use nested loop
l = [1, 6, 3]
nl = []
for number in l:
for i in range(number):
nl.append(number)
print(nl)
or using list comprehension
l = [1,6,3]
nl = [number for number in l for i in range(number)]
#[1, 6, 6, 6, 6, 6, 6, 3, 3, 3]
hello you can make this with the lib itertools:
import itertools
lst = [1,2,3,4,5]
# [1, 2, 3, 4, 5]
list(itertools.chain.from_iterable(itertools.repeat(x, x) for x in lst))
#[1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5]
You have a list of integers, to which the multiplication means arithmetic multiplication. You need to convert them into strings.
A = [1,6,3,8,5,5,2,1,2,10]
new_A = [x * str(x) for x in A]
which is called list comprehension, being a much cleaner/pythonic way of:
for x in A:
new_A.append(x * str(x))
B = np.concatenate([[a]*a for a in A])
>>> array([ 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 8, 8, 8, 8, 8, 8, 8,
8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 1, 2, 2, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10])
nums = [1, 5, 4]
res = []
for num in nums:
res.extend([num] * num)
print(res)
# [1, 5, 5, 5, 5, 5, 4, 4, 4, 4]

Splitting list using a list of indices

I'm trying to split a list into groups based on index pairs from another list, given:
>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> idx = [0, 5]
I need to break up the list resulting in:
>>> l[0:5]
[0, 1, 2, 3, 4]
>>> l[5:]
[5, 6, 7, 8, 9]
The list idx will at a minimum always be [0], but may be of size n; values inside idx will always be sorted ascending.
Currently I have:
>>> l = list(range(10))
>>> idx = [0, 5]
>>> idx.append(None)
>>> [l[idx[i]:idx[i + 1]] for i in range(len(idx) - 1)]
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
Is there a way to accomplish this without explicitly appending Non and iterating over a range?
Edit: for another example...
Given:
>>> l = list(range(14))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
>>> idx = [0, 5, 10]
Desired result:
[[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13]]
You could try about itertools.zip_longest:
from itertools import zip_longest
l = list(range(14))
idx = [0, 5, 10]
print([l[pre: next] for pre, next in zip_longest(idx,idx[1:])])
Result:
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13]]
With numpy you can use numpy.split()
import numpy as np
res =[list(x) for x in np.split(l, idx) if x.size != 0]
print(res)
Output:
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13]]
result = [l[curr_idx:curr_idx+idx[1]] for curr_idx in idx]
result
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13]]

How to shuffle a python list such that the occurrence of some elements are preserved?

I start with a list of integers:
A = [ 1, 2, 5, 3, 4, 6, 7, 8 ]
After a shuffle, I would like some elements (say 3, 4 and 5) to preserve their order of occurrence in A while the rest of the elements are free to be randomly shuffled. Something like:
Outcome #1:
A = [ 5, 2, 3, 1, 8, 4, 6, 7 ]
-or-
Outcome #2:
A = [ 7, 5, 6, 1, 3, 4, 8, 2 ]
-but not-
Outcome #3 (invalid outcome)
A = [7, 4, 6, 1, 3, 5, 8, 2]
Appreciate all suggestions!
Extract the elements you want to maintain relative ordering among, shuffle as normal, then glue the lists back together by randomly picking indexes for the "kept" elements to be inserted. All operations are linear if you use sets for speeding up in operations, which I didn't bother with. Ordering of the keep list matters.
>>> import random
>>> L = [1, 2, 5, 3, 4, 6, 7, 8]
>>> keep = [2, 3, 4]
>>> kept = [L[i] for i in keep][::-1]
>>> unkept = [x for i, x in enumerate(L) if i not in keep]
>>> random.shuffle(unkept)
>>> idxes = random.sample(list(range(len(L))), k=len(keep))
>>> result = [kept.pop() if i in idxes else unkept.pop() for i in range(len(L))]
>>> result
[6, 5, 3, 8, 4, 1, 7, 2]
Random tests:
import random
def shuffle_with_fixed_order(L, keep):
kept = [L[i] for i in keep][::-1]
unkept = [x for i, x in enumerate(L) if i not in keep]
random.shuffle(unkept)
idxes = random.sample(list(range(len(L))), k=len(keep))
return [kept.pop() if i in idxes else unkept.pop() for i in range(len(L))]
if __name__ == "__main__":
for _ in range(5000):
L = list(range(50))
random.shuffle(L)
keep = sorted(random.sample(L, k=20))
shuffled = shuffle_with_fixed_order(L, keep)
new_locs = [shuffled.index(L[i]) for i in keep]
assert all(x < y for x, y in zip(new_locs, new_locs[1:]))
This is one approach using random module
Ex:
import random
A = [ 1, 2, 5, 3, 4, 6, 7, 8 ]
result = A[2:5]
del A[2:5]
while A:
l = len(A)
result.insert(random.randint(0, l), A.pop(random.randrange(l)))
print(result)
Demo
def rand_shfl(lst):
result = lst[2:5]
del lst[2:5]
while A:
l = len(A)
result.insert(random.randint(0, l), A.pop(random.randrange(l)))
return result
for _ in range(10):
A = [ 1, 2, 5, 3, 4, 6, 7, 8 ]
print((rand_shfl(A)))
Output:
[1, 7, 6, 5, 8, 3, 4, 2]
[8, 1, 2, 7, 5, 3, 6, 4]
[8, 6, 7, 2, 1, 5, 3, 4]
[1, 7, 2, 8, 5, 3, 4, 6]
[6, 8, 7, 5, 1, 3, 4, 2]
[7, 2, 5, 6, 1, 3, 4, 8]
[1, 8, 5, 2, 3, 4, 6, 7]
[5, 7, 1, 6, 3, 8, 4, 2]
[1, 5, 7, 3, 2, 4, 8, 6]
[8, 2, 7, 6, 5, 3, 4, 1]
Probably below will work for you
import random
lst=[1, 2, 5, 3, 4, 6, 7, 8]
s_lst = {5:0,3:0,4:0}
idx_lst = [random.randint(0, len(lst)) for i in range(len(s_lst))]
idx_lst.sort()
for i, s in enumerate(s_lst.keys()):
s_lst[s] = idx_lst[i]
lst.remove(s)
random.shuffle(lst)
for k, v in s_lst.items():
lst.insert(v, k)
print(lst)

padding while creating sublists

Is there an elegant way how to pad the last sublist with zeroes while creating sublists from a list of integers?
So far I have this oneliner and need to fill the last sublist with 2 zeroes
[lst[x:x+3] for x in range(0, len(lst), 3)]
for example
lst =[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result should be:
[1,2,3][4,5,6][7,8,9][10,0,0]
With itertools.zip_longest, consuming the same iterator created off of the list, and fill in the missing values as 0 :
[[*i] for i in itertools.zip_longest(*[iter(lst)] * 3, fillvalue=0)]
Example:
In [1219]: lst =[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [1220]: [[*i] for i in itertools.zip_longest(*[iter(lst)] * 3, fillvalue=0)]
Out[1220]: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 0, 0]]
Without itertools:
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print([lst[x:x+3]+[0]*(x-len(lst)+3) for x in range(0, len(lst), 3)])
Prints:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 0, 0]]

Efficiency between two sorting functions

I have created a two functions which sorts integers from lowest value to highest then back to low. Does this type of sort exist? Anyways, I have the following two sorting functions which I have created which produce the same output. I was wondering which is the most efficient of the two? Are there any improvements I can make to either?
sortMiddleMax1
Create a new reverse sorted list of original
Start from index 1 to length of list step by 2
sortMiddleMax2
Sorts the list in-place
Start from last index to 0 step by 2
I tried to make the second more efficient than the first. I did not create a new list in memory and I appended to the end instead of pushing the whole list right. Am I correct in this assumption?
Functions
def sortMiddleMax1(aList=None, verbose=False):
if aList == None or len(aList) < 2:
return aList
else:
sList = sorted(x, key=None, reverse=True)
if verbose: print sList
index = 1
while index < len(sList):
tmp = sList[index]
del sList[index]
sList.insert(0, tmp)
index+=2
if verbose: print sList
return sList
def sortMiddleMax2(aList=None, verbose=False):
if aList == None or len(aList) < 2:
return aList
else:
aList.sort()
if verbose: print aList
index = len(aList)-1
while index > 0:
tmp = aList[index]
del aList[index]
aList.append(tmp)
index-=2
if verbose: print aList
return aList
Main
x = [1,4,6,8,3,5,7,1,5,8,3,9,2,8]
print '############# sortMiddleMax1 #############'
x1 = sortMiddleMax1(x, True)
print '############# sortMiddleMax2 #############'
x2 = sortMiddleMax2(x, True)
Output
############# sortMiddleMax1 #############
[9, 8, 8, 8, 7, 6, 5, 5, 4, 3, 3, 2, 1, 1]
[8, 9, 8, 8, 7, 6, 5, 5, 4, 3, 3, 2, 1, 1]
[8, 8, 9, 8, 7, 6, 5, 5, 4, 3, 3, 2, 1, 1]
[6, 8, 8, 9, 8, 7, 5, 5, 4, 3, 3, 2, 1, 1]
[5, 6, 8, 8, 9, 8, 7, 5, 4, 3, 3, 2, 1, 1]
[3, 5, 6, 8, 8, 9, 8, 7, 5, 4, 3, 2, 1, 1]
[2, 3, 5, 6, 8, 8, 9, 8, 7, 5, 4, 3, 1, 1]
[1, 2, 3, 5, 6, 8, 8, 9, 8, 7, 5, 4, 3, 1]
############# sortMiddleMax2 #############
[1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 8, 8, 9]
[1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 8, 8, 9]
[1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9, 8]
[1, 1, 2, 3, 3, 4, 5, 5, 6, 8, 8, 9, 8, 7]
[1, 1, 2, 3, 3, 4, 5, 6, 8, 8, 9, 8, 7, 5]
[1, 1, 2, 3, 3, 5, 6, 8, 8, 9, 8, 7, 5, 4]
[1, 1, 2, 3, 5, 6, 8, 8, 9, 8, 7, 5, 4, 3]
[1, 2, 3, 5, 6, 8, 8, 9, 8, 7, 5, 4, 3, 1]
You can use Python's extended slicing. [::2] means take every second element. [::-2] means take every second element from the end and work backwards. Here the first slice starts at 0 for even length list and 1 for odd length lists
>>> x = [1, 4, 6, 8, 3, 5, 7, 1, 5, 8, 3, 9, 2, 8]
>>> x = sorted(x)
>>> x[len(x)%2::2] + x[::-2]
[1, 2, 3, 5, 6, 8, 8, 9, 8, 7, 5, 4, 3, 1]
You can use list slice to get the result without for loop:
x = sorted([1,4,6,8,3,5,7,1,5,8,3,9,2,8])
x2 = x[::2] + x[1::2][::-1]
I suspect your two current versions perform exactly the same. However, they both can be improved by using slices to get at the values in the list, rather than by deleting and inserting values.
Each del and each insert is O(N) and you're doing N/2 of each, so the sort will be O(N^2). Slicing is O(N) as well, but only needs to be done twice. The time taken for the sort O(N log N) will dominate, asymptotically.
def sortMiddle3(aList):
s = sorted(aList) # sort the provided list
# now take the even indexed items, followed by the odd indexes in reverse
if len(s) % 2 == 0: # is the number of items even?
return s[::2] + s[-1::-2] # if so, the last item has an odd index
else:
return s[::2] + s[-2::-2]
Example output:
>>> x = [1,4,6,8,3,5,7,1,5,8,3,9,2,8]
>>> sortMiddle3(x)
[1, 2, 3, 5, 6, 8, 8, 9, 8, 7, 5, 4, 3, 1]

Categories

Resources