Related
I have a data list like the following data = [1, 0, 0, 0, 1, 1, 1, 0, 2, 3, 1, 0, 0, 1, 1, 1, 0] and I want to add up the elements of the list to be like this:
[1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 0, 3, 0], where the previous element is the value 0 and the last element other than 0 is the result of the value of the previous number of elements.
I've tried with the following code, if I do the trace, it looks like it can be done, but when I run it it doesn't show results but it's still in the loop that doesn't stop.
I tried it with :
data = [1, 0, 0, 0, 1, 1, 1, 0]
k = len(data)-1
while True:
print(k)
if(data[k-1] == 0):
continue
elif(data[k] == 0):
print("h")
continue
elif(data[k-1] != 0):
data[k] = data[k] + data[k-1]
data[k-1] = 0
k = k-1
if(k == 0):
break
print(data)
Iterate through the list and just add every time a non - zero number
and append a zero to the list.
when there is a 0 appearing just append the sum and make sum 0.
if the last element is 0 add zero to the last number or the
respective last number.
Just remove the first zero and return the list.
.
data = [1, 0, 0, 0, 1, 1, 1, 0, 2, 3, 1, 0, 0, 1, 1, 1, 0]
def calc(data):
sum = 0
new = []
for i in range(len(data)):
if data[i] == 0:
new.append(sum)
if i == len(data) - 1:
new.append(0)
sum = 0
else:
sum = sum = sum + data[i]
new.append(0)
if i == len(data) - 1:
new.append(sum)
if new[0] == 0:
del new[0]
return new
Here is a very simple implementation. I think it is quite self-explanatory. You iterate over each item n in the list, if n is zero, you have two options a) if there is a previous sum x, append x and then n b) if there is no sum, just append 0.
If n is different from zero, sum it to x.
data = [1, 0, 0, 0, 1, 1, 1, 0, 2, 3, 1, 0, 0, 1, 1, 1, 0]
x = 0
r = []
for n in data:
if n == 0:
if x:
r.append(x)
x = 0
r.append(n)
else:
x += n
print(r)
[1, 0, 0, 0, 3, 0, 6, 0, 0, 3, 0]
Iterate through the list and if current and next element are not 0 then add to a temp variable and put current element as 0, when the next element is zero put the value in the current element. Since, code checks for the next element with the current element, Iterate through 2nd last element and check for the last separately.
def arrange_list(arr):
value = 0
for x in range(len(arr)-1):
if arr[x] != 0:
value += arr[x]
else:
value = 0
if arr[x+1] != 0:
arr[x] = 0
else:
arr[x] = value
value = 0
if value !=0:
arr[-1] = value + arr[-1]
return arr
As Mentioned in the Comments you get to an infinite loop because of all the continues. You need to make sure that the line k=k-1 happens to avoid infinite loop.
Second why do while True and then if k==0: break change it to while k>=0.
Anyway your code won't work because it will have a problem with elements that follow a zero.
This code will work:
ans = []
tmp = 0
data = [1, 0, 0, 0, 1, 1, 1, 0]
for curr in data:
if curr != 0:
tmp += curr
elif tmp == 0:
ans.append(tmp)
else:
ans.append(tmp)
ans.append(0)
tmp = 0
print(ans)
You just need to start the value of k from 1 and set elif(data[k] != 0):. However, it will modify your original list.
data=[1, 0, 0, 0, 1, 1, 1, 0, 2, 3, 1, 0, 0, 1, 1, 1, 0]
k = 1
while True:
if(data[k-1] == 0):
pass
elif(data[k] == 0):
pass
elif(data[k] != 0):
data[k] = data[k] + data[k-1]
print(data[k])
data[k-1] = 0
k = k+1
if(k == len(data)):
break
print(data)
Output
3
5
6
2
3
[1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 0, 3, 0]
Here your code is running to infinite loop as you are using continue
statement which will again start the loop from beginning.
As in your case data[k] is zero so the first elif statement is always true
and the continue statement is executing.
Because of the above reason the code k=k-1 line is always unreachable and k value is always 7 in your case. So the while loop is running infinitely.
Below is a suggested code sample which satisfies your use case.
data = [1, 0, 0, 0, 1, 1, 1, 0, 2, 3, 1, 0, 0, 1, 1, 1, 0]
k = len(data)-1
for i in range(0,k):
if(data[i]==0):
continue
if(data[i]!=0 and data[i+1]!=0):
data[i+1]=data[i]+data[i+1]
data[i]=0
print(data)
Why not do it like this:
def convert(A):
B = [0] * len(A)
partial_sum = 0
for i in range(len(A) - 1):
partial_sum += A[i]
if A[i + 1] == 0:
B[i] = partial_sum
partial_sum = 0
if A[-1] != 0:
B[-1] = partial_sum + A[-1]
return B
As opposed to the previous answer, this actually preserves the length of the original array.
You could define a general reusable method which comes in hand in some cases.
Here it is, it returns a generator:
def slice_when(predicate, iterable):
i, x, size = 0, 0, len(iterable)
while i < size-1:
if predicate(iterable[i], iterable[i+1]):
yield iterable[x:i+1]
x = i + 1
i += 1
yield iterable[x:size]
Example of usage
Once you have in place this method, you can use it in this way:
data = [1, 0, 0, 0, 1, 1, 1, 0, 2, 3, 1, 0, 0, 1, 1, 1, 0]
test_method = slice_when(lambda _, y: y==0, data)
list(test_method)
#=> [[1], [0], [0], [0, 1, 1, 1], [0, 2, 3, 1], [0], [0, 1, 1, 1], [0]]
Your case
This is how to apply it for solving your point:
res = []
for e in slice_when(lambda _, y: y==0, data):
res += [0]*(len(e)-1) + [sum(e)]
res
#=> [1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 0, 3, 0]
I have a list of integers which I want to separate according to a certain condition. I want to get the sum and the count of the list elements, stopping when three or more consecutive elements are equal to 0; then the sum and count orders restart again from where they stopped.
For example, part of the list is:
[8, 2, 1, 1, 2, 0, 0, 0, 0, 0, 6, 0, 2, 0, 0, 0, 8, 0, 0, 2, 0, 0, 0, 6, 0, 0]
The process would be:
8, 2, 1, 1, 2 -> sum: 14, length: 5
0, 0, 0, 0, 0
6, 0, 2 -> sum: 8, length: 3
0, 0, 0
8, 0, 0, 2 -> sum: 10, length: 4
0, 0, 0
6, 0, 0 -> sum: 6, length: 3
So the output I want is:
[[14, 5], [8, 3], [10, 4], [6, 3]]
What I've written so far computes the sum okay, but my problem is that zeros within sections aren't counted in the lengths.
Current (incorrect) output:
[[14, 5], [8, 2], [10, 2], [6, 2]]
Code:
arr = [8, 2, 1, 1, 2, 0, 0, 0, 0, 0, 6, 0, 2, 0, 0, 0, 8, 0, 0, 2, 0, 0, 0, 6, 0, 0]
result = []
summed, count = 0, 0
for i in range(0, len(arr) - 2):
el, el1, el2 = arr[i], arr[i + 1], arr[i + 2]
if el != 0:
summed = summed + el
count = count + 1
if el == 0 and el1 == 0 and el2 == 0:
if summed != 0:
result.append([summed, count])
summed = 0
count = 0
elif i == len(arr) - 3:
summed = el + el1 + el2
count = count + 1
result.append([summed, count])
break
print(result)
It is quite hard to understand what your code does. Working with Strings seems more straightforward and readable, your output can be achieved in just two lines (thanks to #CrazyChucky for the improvement):
import re
arr = [8, 2, 1, 1, 2, 0, 0, 0, 0, 0, 6, 0, 2, 0, 0, 0, 8, 0, 0, 2, 0, 0, 0, 6, 0, 0]
# Convert to String by joining integers, and split into substrings, the separator being three zeros or more
strings = re.split(r'0{3,}', ''.join(str(i) for i in arr))
# Sums and counts using list comprehensions
output = [[sum(int(x) for x in substring), len(substring)] for substring in strings]
Output:
>>>output
>>>[[14, 5], [8, 3], [10, 4], [6, 3]]
Remember that readability is always the most important factor in any code. One should read your code for the first time and understand how it works.
If the full list contains numbers with more than one digit, you can do the following:
# Convert to String by joining integers, seperating them by a commade, and split into substrings, the separator being three zeros or more
strings = re.split(r',?(?:0,){3,}', ','.join(str(i) for i in arr))
# Make a list of numbers from those strings
num_lists = [string.split(',') for string in strings]
# # Sums and counts using list comprehensions
output = [[sum(int(x) for x in num_list), len(num_list)] for num_list in num_lists]
This answer is not so much to suggest a way I'd recommend doing it, as to highlight how clever Paul Lemarchand's idea of using a regular expression is. Without Python's re module doing the heavy lifting for you, you have to either look ahead to see how many zeros are coming (as in Prakash Dahal's answer), or keep track of how many zeros you've seen as you go. I think this implementation of the latter is about the simplest and shortest way you could solve this problem "from scratch":
input_list = [8, 2, 1, 1, 2, 0, 0, 0, 0, 0, 6, 0, 2, 0, 0, 0, 8, 0, 0, 2, 0, 0,
0, 6, 0, 0]
output_list = []
current_run = []
pending_zeros = 0
for num in input_list:
# If the number is 0, increment the number of "pending" zeros. (We
# don't know yet if they're part of a separating chunk or not.)
if num == 0:
pending_zeros += 1
# If this is the first nonzero after three or more zeros, process
# the existing run and start over from the current number.
elif pending_zeros >= 3:
output_list.append((sum(current_run), len(current_run)))
current_run = [num]
pending_zeros = 0
# Otherwise, the pending zeros (if any) should be included in the
# current run. Add them, and then the current number.
else:
current_run += [0] * pending_zeros
current_run.append(num)
pending_zeros = 0
# Once we're done looping, there will still be a run of numbers in the
# buffer (assuming the list had any nonzeros at all). It may have
# pending zeros at the end, too. Include the zeros if there are 2 or
# fewer, then process.
if current_run:
if pending_zeros <= 2:
current_run += [0] * pending_zeros
output_list.append((sum(current_run), len(current_run)))
print(output_list)
[(14, 5), (8, 3), (10, 4), (6, 3)]
One note: I made each entry in the list a tuple rather than a list. Tuples and lists have a lot of overlap, and in this case either would probably work perfectly well... but a tuple is a more idiomatic choice for an immutable data structure that will always be the same length, in which each position refers to something different. (In other words, it's not a list of equivalent items, but rather a well-defined combination of (sum, length).)
Use this:
a = [8, 2, 1, 1, 2, 0, 0, 0, 0, 0, 6, 0, 2, 0, 0, 0, 8, 0, 0, 2, 0, 0, 0, 6, 0,0]
total_list = []
i = 0
sum_int = 0
count_int = 0
for ind, ele in enumerate(a):
if ind < (len(a) - 2):
sum_int += ele
if sum_int != 0:
count_int += 1
if (a[ind] == 0) and (a[ind+1] == 0) and (a[ind+2] == 0):
if sum_int != 0:
count_int -= 1
total_list.append([sum_int, count_int])
sum_int = 0
count_int = 0
else:
sum_int += ele
count_int += 1
if sum_int != 0:
total_list.append([sum_int, count_int+1])
sum_int = 0
count_int = 0
print(total_list)
I'm working on a problem which would take this input:
[1, 0, 2, 3, 0, 4, 5, 0]
And output this:
[1, 0, 0, 2, 3, 0, 0, 4]
My function detects zeroes and when a zero is the i-th element of the list, i+1 also becomes a zero and the rest of the list is shifted to make room for it. The elements at the end of the list get pushed out to make room.
I was able to do it with two for loops, but that has O(n^2), and I want to do it in O(n). I came up with this:
new = [0] * len(arr)
zeroes = 0
d = 0
I create a second list of zeroes, zeroes counts the list of zeroes and d is the index to copy for the second list. The array I use is an input into the function and named arr.
First I count zeroes:
for i in range(len(arr)):
if arr[i] == 0:
zeroes+=1
Then I copy. I check by index the value is zero, and if it is, I skip the d-th and d+1-th element.
for i in range(len(arr)-zeroes):
if arr[i] == 0:
d+=1
else:
new[d] = arr[i]
d+=1
However for:
[1, 0, 2, 3, 0, 4, 5, 0]
The output is:
[1, 0, 0, 2, 3, 0, 0, 0]
I'm not sure why the last element doesn't change.
Here is a simpler solution which is still O(n):
a = [1,0,2,3,0,4,5,0]
b = []
for i in a:
b.append(i)
if i == 0:
b.append(0)
b = b[:len(a)]
The value of b would be
[1, 0, 0, 2, 3, 0, 0, 4]
Having a bit of writing out the code.
For example, if I have an array of:
a = ([0, 0, 1, 2], [0, 1, 1, 0], [0, 0, 1, 0], [1, 0, 1, 3], [0, 1, 1, 3])
if I want to add first element of each item,
as in to return a list of 0 + 0 + 0 + 1 + 0, 0 + 1 + 0, 0 + 0 ...
I wrote the code:
def test(lst):
sum = 0
test_lst = []
i = 0
while i in range(0, 4):
for j in range(0, len(lst)):
sum += lst[j][i]
test_lst.append(sum)
i += 1
return test_lst
I get index size error.
How can I go about this?
sum(zip(*a)[0])
zip is a function that takes any number of n-length sequences and returns n tuples (among other things). The first of these tuples has the elements that came first in the tuples passed to zip. sum adds them together.
EDIT:
In Python 3, the above doesn't work. Use:
sum(next(zip(*a)))
instead. For all such sums,
map(sum, zip(*a))
a = ([0, 0, 1, 2], [0, 1, 1, 0], [0, 0, 1, 0], [1, 0, 1, 3], [0, 1, 1, 3])
Try using list comprehensions:
sum([item[0] for item in a])
The line above takes the first element of each list in the tuple, then puts it into a temporary list. We then call sum on that temporary list, which yields the answer.
Seemingly straightforward problem: I want to create an array that gives the count since the last occurence of a given condition. In this condition, let the condition be that a > 0:
in: [0, 0, 5, 0, 0, 2, 1, 0, 0]
out: [0, 0, 0, 1, 2, 0, 0, 1, 2]
I assume step one would be something like np.cumsum(a > 0), but not sure where to go from there.
Edit: Should clarify that I want to do this without iteration.
Numpy one-liner:
x = numpy.array([0, 0, 5, 0, 0, 2, 1, 0, 0])
result = numpy.arange(len(x)) - numpy.maximum.accumulate(numpy.arange(len(x)) * (x > 0))
Gives
[0, 1, 0, 1, 2, 0, 0, 1, 2]
If you want to have zeros in the beginning, turn it to zero explicitly:
result[:numpy.nonzero(x)[0][0]] = 0
Split the array based on the condition and use the lengths of the remaining pieces and the condition state of the first and last element in the array.
A pure python solution:
result = []
delta = 0
for val in [0, 0, 5, 0, 0, 2, 1, 0, 0]:
delta += 1
if val > 0:
delta = 0
result.append(delta)