sum multiple list elements at the same time(python) - python

How can I sum multiple list elements at the same time?
For example, something like this in Python:
Our lists (input):
[3, 3, 1, 1, 1, 1, 1]
[1, 1, 4, 5, 6, 7, 8]
Output:
[4, 4, 5, 6, 7, 8, 9]
Note: we don't know how many list will be given to us.

This should do the job
l1 = [3, 3, 1, 1, 1, 1, 1]
l2 = [1, 1, 4, 5, 6, 7, 8]
l3 = [sum(t) for t in zip(l1, l2)]
print(l3)

As we don't know how many lists there will be, and I assume their lengths could be different, using the zip_longest function from itertools is the perfect tool:
from itertools import zip_longest
l1 = [3, 3, 1, 1, 1, 1, 1]
l2 = [1, 1, 4, 5, 6, 7, 8]
l3 = [1, 1, 4, 5, 6, 7, 8, -1]
l4 = [-105]
lists = [l1,l2,l3,l4]
summed = list(map(sum,zip_longest(*lists,fillvalue=0)))
print(summed)
Output:
[-100, 5, 9, 11, 13, 15, 17, -1]

This can be done very easily and efficiently using pandas.
lists = [[3, 3, 1, 1, 1, 1, 1], [1, 1, 4, 5, 6, 7, 8]]
df = pd.DataFrame(data=lists)
out = df.sum().tolist()
print(out):
[4, 4, 5, 6, 7, 8, 9]
It should work with any number of lists.

If you have varying number of list as input , you can try the below.,
note : input the numbers in list as comma-seperated values
Console
1,2,3
2,3,1
[3, 5, 4]
import pandas as pd
ls = []
while True:
inp = input()
if inp == "":
break
ls.append(list(map(int,inp.split(","))))
df = pd.DataFrame(data=ls)
out = df.astype(int).sum().tolist()
print(out)

Related

How to expand a list to a certain size without repeating each individual list elements that n-times?

I'm looking to keep the individual elements of a list repeating for x number of times, but can only see how to repeat the full list x number of times.
For example, I want to repeat the list [3, 5, 1, 9, 8] such that if x=12, then I want to produce tthe following list (i.e the list continues to repeat in order until there are 12 individual elements in the list:
[3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5]
I can do the below but this is obviously not what I want and I'm unsure how to proceed from here.
my_list = [3, 5, 1, 9, 8]
x = 12
print(my_list * 12)
[3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5, 1, 9, 8]
Your code repeats list 12 times. You need to repeat list until length is matched. This can achieved using Itertools - Functions creating iterators for efficient looping
from itertools import cycle, islice
lis = [3, 5, 1, 9, 8]
out = list(islice(cycle(lis), 12))
print(out)
Gives #
[3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5]
More pythonic #
Use a for loop to access each element in list and iterate over 'length' times. Repeat Ith element you access through loop in same list until length matches.
lis = [3, 5, 1, 9, 8]
length = 12
out = [lis[i%len(lis)] for i in range(length)]
print(out)
Gives ##
[3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5]
There are multiple ways to go about it. If x is the final length desired and lst is the list (please do not use list as a variable name because it overwrites the builtin list function), then you can do :
lst = (lst * (1 + x // len(lst)))[:x]
This multiplies the list by the smallest number needed to get at least N elements, and then it slice the list to keep only the first N. For your example :
>>> lst = [3, 5, 1, 9, 8]
>>> x = 12
>>> (lst * (1 + x // len(lst)))[:x]
[3, 5, 1, 9, 8, 3, 5, 1, 9, 8, 3, 5]
You could also use a loop, for example :
index = 0
while len(lst) < x:
lst.append(lst[index])
index += 1

Python: How to split a list into ordered chunks

If I have the following list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Then
np.array_split([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 3)
Returns
[array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8, 9])]
Is there a way to get the sub-arrays in the following order?
[array([0, 3, 6, 9]), array([1, 4, 7]), array([2, 5, 8])]
As the lists are of differing lengths, a numpy.ndarray isn't possible without a bit of fiddling, as all sub-arrays must be the same length.
However, if a simple list meets your requirement, you can use:
l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l2 = []
for i in range(3):
l2.append(l[i::3])
Output:
[[0, 3, 6, 9], [1, 4, 7], [2, 5, 8]]
Or more concisely, giving the same output:
[l[i::3] for i in range(3)]
Let's look into source code refactor of np.array_split:
def array_split(arr, Nsections):
Neach_section, extras = divmod(len(arr), Nsections)
section_sizes = ([0] + extras * [Neach_section + 1] + (Nsections - extras) * [Neach_section])
div_points = np.array(section_sizes).cumsum()
sub_arrs = []
for i in range(Nsections):
st = div_points[i]
end = div_points[i + 1]
sub_arrs.append(arr[st:end])
return sub_arrs
Taking into account your example arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] and Nsections = 3 it will construct section sizes [0, 4, 3, 3] and dividing points [0, 4, 7, 10]. Then do something like this:
[arr[div_points[i]:div_points[i + 1]] for i in range(3)]
Trying to mimic behaviour of numpy, indeed,
def array_split_withswap(arr, N):
sub_arrs = []
for i in range(N):
sub_arrs.append(arr[i::N])
Is the best option to go with (like in #S3DEV solution).

sample n random permutations of a list in python [duplicate]

This question already has answers here:
python shuffling with a parameter to get the same result
(4 answers)
Closed 1 year ago.
I have a list of values such as:
lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
and I need to reproducibly return n random shuffles of this list.
Ideally, I need a function with seed such that f(lst, samples = 2, seed = 1234)
-> return two shuffles of the list lst such as:
[5, 7, 1, 6, 2, 8, 0, 4, 3, 9]
[8, 7, 3, 0, 1, 4, 5, 9, 6, 2]
Repeated execution of this function (with the same seed) would return the same two lists.
This works without numpy:
import sys
import random
some_seed = 123 # change this to get different shuffles
def n_shuffles(lst, n):
r = random.Random(some_seed)
for _ in range(n):
_l = lst[:]
r.shuffle(_l)
yield _l
l = list(range(10))
>>> [*n_shuffles(l, 3)]
[[8, 7, 5, 9, 2, 3, 6, 1, 4, 0], [7, 6, 3, 4, 1, 0, 2, 5, 9, 8], [1, 8, 5, 6, 4, 7, 9, 0, 2, 3]]
>>> [*n_shuffles(l, 3)]
[[8, 7, 5, 9, 2, 3, 6, 1, 4, 0], [7, 6, 3, 4, 1, 0, 2, 5, 9, 8], [1, 8, 5, 6, 4, 7, 9, 0, 2, 3]]
You can use np.copy
import numpy as np
lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
def shuffle_list(arr:list,samples:int,seed:int):
np.random.seed(seed)
res = []
for i in range(samples):
arr_copy=np.copy(arr)
np.random.shuffle(arr_copy)
res.append(arr_copy)
return res
#test
print(shuffle_list(lst,2,1234))
output:
[array([7, 2, 9, 1, 0, 8, 4, 5, 6, 3]), array([7, 3, 5, 1, 4, 8, 0, 2, 6, 9])]
Ok, it wasn't an exact duplicate, but the proposed topic has pretty much shown that re-setting the seed() is the key:
import random
def shuffles(l,n):
random.seed(4) # just the same one as in the referred topic
return [random.sample(l,k=len(l)) for i in range(n)]
print(shuffles([1,2,3,4],3))
print("again:")
print(shuffles([1,2,3,4],3))
will generate
[[2, 4, 1, 3], [4, 1, 3, 2], [1, 2, 3, 4]]
again:
[[2, 4, 1, 3], [4, 1, 3, 2], [1, 2, 3, 4]]

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)

Looking backward and forward in a circular loop in python

I would like to generate a list of single digits based on user input. In a circular iterative way, the list should contain the user input, the two digits before that, and the two digits after that. The order of the digits isn't important.
user_input = "1"
output = [9, 0, 1, 2, 3]
user_input = "9"
output = [7, 8, 9, 0, 1]
Using itertools.cycle I was able to get the next two digits, but I couldn't find an answer that can help me get the previous two digits. Is there a simple way to get those previous two digits?
from itertools import cycle
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
user_input = "139"
for i in user_input:
s = int(i)
lst = [s]
itr = cycle(numbers)
if s in itr:
#how can I get the two digits before s?
lst.append(next(itr)) #getting the next digit
lst.append(next(itr))
print(lst)
Could use a list comprehension and % 10:
>>> for s in range(10):
print([i % 10 for i in range(s-2, s+3)])
[8, 9, 0, 1, 2]
[9, 0, 1, 2, 3]
[0, 1, 2, 3, 4]
[1, 2, 3, 4, 5]
[2, 3, 4, 5, 6]
[3, 4, 5, 6, 7]
[4, 5, 6, 7, 8]
[5, 6, 7, 8, 9]
[6, 7, 8, 9, 0]
[7, 8, 9, 0, 1]
You can implement like this.
def backward_list(n):
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
if n == 0 or n == 1:
x = numbers.index(n)
else:
x = (numbers.index(n)-10)
return [numbers[x-2],numbers[x-1],numbers[x],numbers[x+1],numbers[x+2]]
Execution
In [1]: for i in range(10):
.....: print backward_list(i)
.....:
[8, 9, 0, 1, 2]
[9, 0, 1, 2, 3]
[0, 1, 2, 3, 4]
[1, 2, 3, 4, 5]
[2, 3, 4, 5, 6]
[3, 4, 5, 6, 7]
[4, 5, 6, 7, 8]
[5, 6, 7, 8, 9]
[6, 7, 8, 9, 0]
[7, 8, 9, 0, 1]
Modify your statements in the iff to this:
if s in itr and len(str) == 2:
lst.append(next(itr)) #getting the next digit
lst = [s - 1] + lst # prepend the first value
lst.append(next(itr))
lst = [s - 2] + lst # prepend the second value
Or you can also do
if s in itr and len(str) == 2:
lst.append(next(itr)) #getting the next digit
lst.insert(0, s-1) # prepend the first value
lst.append(next(itr))
lst.insert(0, s-2) # prepend the second value
You could take a range from the input and use that range to slice a numpy array
edit: my bad for writing code and not testing it... thanks #Stefan Pochmann for pointing that out...
import numpy as np
def cycle(x): #x is user input
indices = np.array(range(x-2, x+3))%10
numbers = np.array(range(10))
return numbers[indices]

Categories

Resources