I'm very new to python. I'm trying to create a loop so that I can get cumulative sums of the elements in a list. For example, given a list [3, 2, 1] I'm hoping to get [3 (first number), 5 (3+2), 6 (3+2+1)], [2 (second number), 3 (2+1)] and [1].
What I have currently is:
data = [5, 4, 3, 2, 1]
for i in data:
perf = [sum(data[:i+1]) for i in range(len(data))]
print(perf)
And I'm getting the following as output, which is the sum from the first element. How do I modify to get the cumulative sums starting with 4, 3, ... ?
[5, 9, 12, 14, 15]
[5, 9, 12, 14, 15]
[5, 9, 12, 14, 15]
[5, 9, 12, 14, 15]
[5, 9, 12, 14, 15]
My desired output
[5, 9, 12, 14, 15]
[4, 7, 9, 10]
[3, 5, 6]
[2, 3]
[1]
Thank you!
If I understand you correctly, in the 1. iteration you want to get sums from first element, in the 2. iteration sums from second element and so on:
data = [5, 4, 3, 2, 1]
for i in range(len(data)):
s = 0
l = [s := s + d for d in data[i:]]
print(l)
Prints:
[5, 9, 12, 14, 15]
[4, 7, 9, 10]
[3, 5, 6]
[2, 3]
[1]
Or: using itertools.accumulate
from itertools import accumulate
data = [5, 4, 3, 2, 1]
for i in range(len(data)):
print(list(accumulate(data[i:])))
You're not far from the answer. You just need to begin your range from the next num in the list. Try this:
data = [5, 4, 3, 2, 1]
for ind, num in enumerate(data):
perf = [sum(data[ind:i+1]) for i in range(ind, len(data))]
print(perf)
Output:
[5, 9, 12, 14, 15]
[4, 7, 9, 10]
[3, 5, 6]
[2, 3]
[1]
Your statement to compute a commulative sum within the loop is correct.
You had just used i incorrectly in the outer loop statement.
All you need to do is slice your original data and generate sums for each slice.
test_data = [5, 4, 3, 2, 1]
def commulative_sum(a_list: list[int]):
# The same thing you wrote
return [sum(a_list[:i+1]) for i in range(len(a_list))]
def commulative_sums(data: list[int]):
# Slice the input data and generate commulative sums
return [commulative_sum(data[j:]) for j in range(len(data))]
result = commulative_sums(test_data)
print(result)
[[5, 9, 12, 14, 15], [4, 7, 9, 10], [3, 5, 6], [2, 3], [1]]
Here are 2 ways you can solve this problem.
data = [5, 4, 3, 2, 1]
k = 0;
for i in data:
k = k + i
print(k)
And this is the second method
data = [5, 4, 3, 2, 1]
k = 0;
for i in range(len(data)):
k = k + data[i]
print(k)
Related
This question already has answers here:
Running through combinations of 4 numbers
(2 answers)
Closed 1 year ago.
How to find all possible of array switching?
Example
Original Value: [10,5,3,6]
Output:
[10, 5, 3, 6]
[5, 3, 6, 10]
[3, 6, 10, 5]
[6, 10, 5, 3]
[10, 3, 5, 6]
[3, 5, 6, 10]
[5, 6, 10, 3]
[6, 10, 3, 5]
[10, 5, 6, 3]
[5, 6, 3, 10]
[6, 3, 10, 5]
[3, 10, 5, 6]
[10, 6, 5, 3]
[6, 5, 3, 10]
[5, 3, 10, 6]
[3, 10, 6, 5]
[3, 6, 5, 10]
[6, 5, 10, 3]
[5, 10, 3, 6]
[10, 3, 6, 5]
[3, 10, 5, 6]
[10, 5, 6, 3]
[5, 6, 3, 10]
[6, 3, 10, 5]
....
This is not the end of the list, but I am looking for something that can output all combinations of array, given placement should be considered.
For now, I've comeout with something to switch the place
def rotateArray(arr, n, d):
temp = []
i = 0
while (i < d):
temp.append(arr[i])
i = i + 1
i = 0
while (d < n):
arr[i] = arr[d]
i = i + 1
d = d + 1
arr[:] = arr[: i] + temp
return arr
spam = [3, 10, 5, 6]
for i in range(0,len(spam)):
spam = [3, 10, 5, 6]
a = rotateArray(spam, len(spam), i)
print(a)
That will switch by 1 place of all value, but not random switching.
You can use a built-in function:
from itertools import permutations
arr = [10, 5, 3, 6]
print(list(permutations(arr)))
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]]
I have a project wherein I have to get the follow-up elements of elements in on_time.
For example:
j_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
s_follow_int = [[2, 3], 4, [5, 6], [6, 8], [7, 8], 9, 8, 10, 10, 11]
on_time = [4, 5]
The code I have looks like this:
# element in on_time except 1, get follow_finish_act
follow_finish_act = []
for a, d in zip(j_set, s_follow_int):
if a in on_time and a != 1:
if len(on_time) > 1:
follow_finish_act.append(d)
else:
follow_finish_act = d
Output I am getting:
follow_finish_act = [[6, 8], [7, 8]]
Expected Output:
follow_finish_act = [6, 7, 8]
I am having trouble when length of on_time is more than 1. I think the problem is flattening the irregular lists (can be nested and integer) without duplicates. Since, I cannot get my expected output.
Any help/suggestions would be appreciated! Thank you!
Edit: Code I used for trying to flatten output of follow_finish_act
def flatten(lss):
for item in lss:
try:
yield from flatten(item)
except TypeError:
yield item
You could avoid duplicates by using set instead of list
j_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
s_follow_int = [[2, 3], 4, [5, 6], [6, 8], [7, 8], 9, 8, 10, 10, 11]
on_time = [4, 5]
follow_finish_act = set()
for a, d in zip(j_set, s_follow_int):
if a in on_time and a != 1:
if len(on_time) > 1:
follow_finish_act.update(d)
else:
follow_finish_act.update(d)
print(follow_finish_act)
# prints {6,7,8}
print(list(follow_finish_act))
# prints[8,7,6]
Its difficult to tell what you really want, but looking at the code a lot of it seems superfluous. Try this instead:
j_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
s_follow_int = [[2, 3], 4, [5, 6], 8, 7, 9, 8, 10, 10, 11]
on_time = [6, 5]
follow_finish_act = []
for a, d in zip(j_set, s_follow_int):
if a in on_time:
follow_finish_act.append(d)
print(follow_finish_act)
Output:
[7, 9]
If you then get output like: [9], you could do this afterwards:
if len(follow_finish_act) == 1:
follow_finish_act = follow_finish_act[0]
Let's say this is my list:
[5, 3, 13, 8, 1, 2, 6, 4, 10, 1, 12, 3, 7, 1, 4]
I want to break it into chunks respecting a maximum sum of 12 when possible so that the result should be like this:
[[5, 3], [13], [8, 1, 2], [6, 4], [10, 1], [12], [3, 7, 1], [4]]
Notice the code should not delete any integer greater than the maximum sum (in our case 13) but keep it isolated in a sublist.
I managed to do that with this code:
lst = [5, 3, 13, 8, 1, 2, 6, 4, 10, 1, 12, 3, 7, 1, 4]
start = 0
stop = 1
max_chunk_sum = 12
lst_count = len(lst)
result = []
while not stop > lst_count:
chunk = lst[start:stop]
chunk_sum = sum(chunk)
chunk_count = len(chunk)
if chunk_sum < max_chunk_sum:
if stop != lst_count:
stop += 1
else:
result.append(lst[start:stop])
break
else:
if chunk_count == 1:
result.append(lst[start:stop])
start = stop
stop += 1
else:
stop -= 1
result.append(lst[start:stop])
start = stop
stop += 1
print(result)
Output:
[[5, 3], [13], [8, 1, 2], [6, 4], [10, 1], [12], [3, 7, 1], [4]]
But I feel there's a much smarter solution for this problem (maybe using list comprehension?).
You could use a list comprehension, but you could just check if the sum of adding the next element to the previous list would break the maximum value, if it does, append a new list.
result = [[lst.pop(0)]]
for item in lst:
if sum(result[-1]) + item > max_chunk_sum:
result.append([item])
else:
result[-1].append(item)
Here I iterate over lst, I use a sublist chunk, I check if this chunk would be > 12, otherwise I append the new element i in chunk. If it would be > 12, then I append the chunk to result, and I create a new chunk.
lst = [5, 3, 13, 8, 1, 2, 6, 4, 10, 1, 12, 3, 7, 1, 4]
max_chunk_sum = 12
result = []
chunk = []
for i in lst:
if sum(chunk) + i <= max_chunk_sum:
chunk.append(i)
else:
if chunk:
result.append(chunk)
chunk = [i]
result.append(chunk)
print(result)
Output :
[[5, 3], [13], [8, 1, 2], [6, 4], [10, 1], [12], [3, 7, 1], [4]]
Similar to #phoenixo, but we can use a generator:
def cluster(iterable, max_int):
start, *iterable = iterable
cluster = [start]
for value in iterable:
if sum(cluster) + value <= max_int:
cluster.append(value)
else:
yield cluster
cluster = [value]
yield cluster
Which gives us:
In [204]: list(cluster(ints, 12))
Out[204]: [[5, 3], [13], [8, 1, 2], [6, 4], [10, 1], [12], [3, 7, 1], [4]]
You could use accumulate to compute the running sums with breaks on chunk overruns. Then use these sums to determine the ranges of indexes to include in each group:
a = [5, 3, 13, 8, 1, 2, 6, 4, 10, 1, 12, 3, 7, 1, 4]
chunk = 12
from itertools import accumulate
sums = accumulate(a,lambda s,v: [s+v,v][s+v>chunk])
breaks = [ i+1 for (i,s),v in zip(enumerate(sums),a[1:]) if s+v>chunk]
groups = [ a[s:e] for s,e in zip([0]+breaks,breaks+[len(a)]) ]
print(groups)
# [[5, 3], [13], [8, 1, 2], [6, 4], [10, 1], [12], [3, 7, 1], [4]]
If you're looking for a solution without using libraries, here's a simple loop that will do it without using sum and without adding values multiple times :
array = [5, 3, 13, 8, 1, 2, 6, 4, 10, 1, 12, 3, 7, 1, 4]
chunk = 12
group,total = [],0
groups = [group]
for value in array:
total += value
if total > chunk:
group,total = [],value
groups.append(group)
group.append(value)
print(groups)
# [[5, 3], [13], [8, 1, 2], [6, 4], [10, 1], [12], [3, 7, 1], [4]]
This is a typical work for reduce...
from functools import reduce
lst = [5, 3, 13, 8, 1, 2, 6, 4, 10, 1, 12, 3, 7, 1, 4]
init = lst[0:1]
rest = lst[1:]
max_sum = 12
reduce(lambda acc, cur: [*acc[0:-1], [*acc[-1], cur]]
if sum(acc[-1]) + cur <= max_sum else
[*acc, [cur]],
rest,
[init])
PS: it's also a pure function (immutable)...
x1 = [1, 2, 3, 4, 5, 6]
x2 = [3, 5, 6, 8, 9]
x3 = [2, 4, 5, 7, 13]
x4 = [11, 22, 33, 24, 55, 66]
x5 = [11, 7, 1, 2, 3, 4, 5, 6]
How do I remove the increasing values on every list?
If I removed the increasing in those lists, they should look like this:
x1 = [1, 6]
x2 = [3, 9]
x3 = [2, 13]
x4 = [11, 33, 24, 66]
x5 = [11, 7, 1, 6]
You can use a generator to build up the runs and yield the results, e.g.:
def runs(iterable):
iterable = iter(iterable)
i = [next(iterable)] # Empty iterable not handled
for j in iterable:
while j and i[-1] < j:
i.append(j)
j = next(iterable, None)
i[1:-1] = [] # Removes the middle of the run, if there is one
yield from i
i = [j]
if j:
yield j
# Using #StephenRauch data set
data = (
[1, 2, 3, 4, 5, 6],
[3, 5, 6, 8, 9],
[2, 4, 5, 7, 13],
[11, 22, 33, 24, 55, 66],
[11, 7, 1, 2, 3, 4, 5, 6]
)
>>> [list(runs(d)) for d in data]
[[1, 6], [3, 9], [2, 13], [11, 33, 24, 66], [11, 7, 1, 6]]
This will remove any increasing elements:
Code:
def remove_increasing(a_list):
return [a_list[0]] + \
[y for x, y in zip(a_list, a_list[1:]) if x >= y] + \
[a_list[-1]]
Test Code:
data = (
[1, 2, 3, 4, 5, 6],
[3, 5, 6, 8, 9],
[2, 4, 5, 7, 13],
[11, 22, 33, 24, 55, 66],
[11, 7, 1, 2, 3, 4, 5, 6]
)
for d in data:
print(remove_increasing(d))
Results:
[1, 6]
[3, 9]
[2, 13]
[11, 24, 66]
[11, 7, 1, 6]
Your question is unclear. What does "remove the increasing values" mean?
Clearly you don't mean "remove every value that is larger than the previous one", because your example results include the last element which is larger.
But, assuming you know what you mean, here's how to do it:
To delete a value from a list:
mylist.remove(4)
To remove the item at a specific position from a list: (remember that Python lists start at position zero, not position one)
del mylist[2]