Find first non zero numbers in an array (zeroes can be anywhere) - python

Suppose we have an array: x = [10,0,30,40]. I would like to extract the first non zero element and store it in a different variable, say y. In this example, y = 10. We can also have many zeros, x = [0,0,30,40], which should give y = 30 as the extracted value.
I tried a Python snippet like this:
i = 0
while x[i] != 0:
y = arr[i]
if x[i] == 0:
break
This only works if the array is [10,0,30,40]. It does not work if I have 0,20,30,40. The loop would stop before that. What is an efficient way to implement this? I try not to use any special Numpy functions, just generic common loops because I might need to port it to other languages.

You can do this
x = [10,0,30,40]
for var in x:
if var != 0:
y = var
break

You could use list comprehension to get all the non-zero values, then provided there are some non-zero values extract the first one.
x = [10,0,30,40]
lst = [v for v in x if v != 0]
if lst:
y = lst[0]
print(y)

The problem with your code is that you don't increment i so it's stuck on the first element. So what you could do to keep the code portable is:
while x[i] != 0:
y = x[i]
if x[i] == 0:
break
i+=1
This code is still not clean, because if there is no 0 in your array then you will get an IndexError as soon as you reach the end.

I'm kind of new to this but i think this should work:
x = [0, 12, 24, 32, 0, 11]
y = []
for num in x:
if num != 0:
y.append(num)
break
print(y)

You can use the next function:
x = [10,0,30,40]
next(n for n in x if n) # 10
x = [0,0,30,40]
next(n for n in x if n) # 30
if you need to support the absence of zero in the list, you can use the second parameter of the next() function:
x = [0,0,0,0]
next((n for n in x if n),0) # 0

Related

Python: Comparing values in two lists

I've really tried looking all over for solutions to my problem but haven't been successful in finding anything. If someone else has already asked this question, I apologize. Onto the problem.
I have two lists in with values to be compared to each other. I have tried the following option.
list1 = [1,3,5,7,9]
list2 = [200,2]
x = 0
n = 0
y = 0
while x <= 9:
if list1[y] >= list2[n]:
print('TRUE')
x = x + 1
y = y + 1
if y > 4:
y = 0
n = n + 1
else:
print('FALSE')
x = x + 1
y = y + 1
if y > 4:
y = 0
n = n + 1
The only problem is, instead of the variables in place, I need to iterate through a list of values.
So instead, I would like the code to look something like this:
x = 0
n = [0,1]
y = [0,3]
z = len(n) + len(y) - 1
while x <= z:
if list1[y] >= list2[n]:
print('TRUE')
x = x + 1
else:
print('FALSE')
x = x + 1
Where n and y are index values of the numbers that I want to compare.
This does not work for me and I'm really not sure how else to do this.
Edit: I didn't think I had to explain everything by text since I included two sets of code. The first set of code works and it shows exactly what I am trying to do. The second is what I want it to do.
Broken down further I want to know if list1[0]>=list2[0], followed by list1[3]>=list2[0], followed by list1[0]>=list2[1], followed by list1[3]>=list2[1]. The outputs that I expect are in the code I provided.
Apologies if I wasn't clear before. I need to call specific index positions that I will have in a separate list. This is the problem that I tried to outline in the second code.
I think now get what you are trying to do.
First, there are two lists of "raw" data:
list1 = [1,3,5,7,9]
list2 = [200,2]
Then, there are two sets of "indices of interest":
y = [0, 3] # indices of interest for list1
n = [0, 1] # indices of interest for list2
I think the following can achieve what you want:
product = [(index1, index2) for index2 in n for index1 in y] #cartesian product
for index1, index2 in product:
if list1[index1] >= list2[index2]:
print("True")
else:
print("False")
Or if the cartesian product is not wanted, simply do it within nested loops:
for index2 in n:
for index1 in y:
if list1[index1] >= list2[index2]:
print("True")
else:
print("False")

Sum of random list numbers after 1st negative number

import random
def mainlist(list, size, min, max):
for i in range(size):
list.append(random.randint(min, max))
print(list)
def counterlist(list):
for i in list:
if i<0:
x=sum(list[(list.index(i)+1):])
print('Reqemlerin cemi:', x)
break
list = []
mainlist(list, 10, -10, 30)
counterlist(list)
I need to calculate sum of numbers after 1st negative number in this random list, did it in second function but want to know is there way not using the sum() function?
Explicitly using an iterator makes it nicer and more efficient:
def counterlist(lst):
it = iter(lst)
for i in it:
if i < 0:
print('Reqemlerin cemi:', sum(it))
No idea why you wouldn't want to use the sum function, that's absolutely the right and best way to do it.
Try this:
import random
lst = [random.randint(-10, 30) for _ in range(10)]
print(sum(lst[next(i for i, n in enumerate(lst) if n < 0) + 1:]))
First you generate the list lst. Then, you iterate over your list and you find the first negative element with next(i for i, n in enumerate(lst) if n < 0). Finally, you compute the sum of the portion of the list you're interested about.
If you really don't want to use sum but keep things concise (and you're using python >= 3.8):
import random
lst = [random.randint(-10, 30) for _ in range(10)]
s = 0
print([s := s + x for x in lst[next(i for i, n in enumerate(lst) if n < 0) + 1:]][-1])
Assuming there's a negative value in the list, and with a test list "a":
a = [1,2,3,-7,2,3,4,-1,23,3]
sum(a[(a.index([i for i in a if i < 0][0]) + 1):])
Evaluates to 34 as expected. Could also add a try/except IndexError with a simple sum to catch if there's no negative value.
Edit: updated the index for the search.
Yes, you can iterate over the elements of the list and keep adding them to some var which would store your result. But what for? sum approach is much more clear and python-ish.
Also, don't use list as a list name, it's a reserved word.
# After you find a first negative number (at i position)
j = i + 1
elements_sum = 0
while j < len(list):
elements_sum += list[j]
j += 1
Not as good as the marked answer, but just to know how to make use of numpy, being sure there is a negative number in the list.
Sample list: lst = [12, 2, -3, 4, 5, 10, 100]
You can get your result using np.cumsum:
import numpy as np
np_lst = np.array(lst)
cum_sum = np.cumsum(np_lst)
res = cum_sum[-1] - cum_sum[np_lst<0][0]
res #=> 119
First of all don't use list as a variable name, it's a reserved keyword. Secondly, make your loop as follows:
for index, x in enumerate(list_):
if x < 0:
sum_ = sum(list_[(index + 1):])
print('Reqemlerin cemi:', sum_)
break
That way, you don't need to find a value.
At last if you don't want to use sum
found_negative = false
sum_ = 0
for x in list_:
if found_negative:
sum_ += x
elif x < 0:
found_negative = true
print('Reqemlerin cemi:', sum_)

TypeError: string indices must be integers..what is the problem

i'm getting TypeError: string indices must be integers... how can i solve this?
And the code is:
def myfunc(x):
y=''
for i in x:
y=y+x[i].upper() +x[i+1]
i+=2
return y
Try to avoid iterating over indices when possible. You can do that there by iterating over x zipped with its own tail:
def myfunc(x):
y = ''
for x1, x2 in zip(x, x[1:]):
y = y + x1.upper() + x2
return y
Even better (and more efficient), you can use join to create y from one list.
import itertools
def myfunc(x):
return ''.join(list(itertools.chain.from_iterable(x1.upper() + x2 for x1,x2 in zip(x, x[1:]))))
You should index x iterating over the actual indices of x, not its values, thus doing range(len(x)), or enumerate(x). Also you cannot modify the iterator in a for loop, you need a while if you want to do so:
def myfunc(x):
y=''
i = 0
while i < len(x) - 1:
y=y+x[i].upper() +x[i+1]
i+=2
return y
When you say: for i in x: is it like you are saying "for each letter in the x string", so at every iteration, i will be the next letter from the string. You can create a simple loop like you have with a print i statement to see the behavior.
Another problem with your code is the x[i + 1] statement. When the for loop will reach the last iteration, you'll try to access something non-existent and you'll get an IndexError. This being said, you should modify your code like this:
def myfunc(x):
y = ''
for i in range(0, len(x) - 1, 2):
y = y + x[i].upper() + x[i + 1]
return y
Because you want to iterate every other character, I also used another set of parameters for range: range([start], stop[, step]).
start: Starting number of the sequence.
stop: Generate numbers up to, but not including this number.
step: Difference between each number in the sequence.
Cheers!
You can do that with enumerate:
Code:
x = 'abcdef'
def myfunc(x):
y = ''
c = 0
for i, j in enumerate(x):
if i == c:
y += j.upper()
else:
y += j
c += 2
return(y)
assert myfunc(x) == 'AbCdEf'
print(myfunc(x))
Output:
AbCdEf

Partial Digest Problem(PDP) in python only spits out "None"

Partial Digest Problem is one of the algorithms for getting the places of cut in DNA. Given all the possible lengths of cut, for example [2,2,3,3,4,5,6,7,8,10] I have to figure out a way to find the actual places of cut. In this example total length of the DNA is 10, and the places of actual cut are [0,3,6,8,10].
From the algorithm above, I'm trying to build the actual code in python, and with hand I'm not sure what I've done wrong.
The desired output for this code is
[0,3,6,8,10]
where I'm only getting
"None"
Can anyone please tell me what part in my code is wrong?
# function to remove multiple elements given as list
def delete(elements,A):
for el in elements:
A.remove(el)
return A
# y is given as integer, X as list
def delta(y,X):
n = len(X)
for i in range(n):
X[i] -= y
X[i] = abs(X[i])
return sorted(X)
# If former contains latter, return true. Else, return false
def contains(small, big):
for i in range(len(big)-len(small)+1):
for j in range(len(small)):
if big[i+j] != small[j]:
break
else:
return True
return False
def partialDigest(L):
global width
width = (max(L))
delete([width], L) # Needs to be in list to feed to 'delete' function
X = [0, width]
X = place(L,X)
return X
def place(L,X):
if len(L) == 0: # Baseline condition
return X
y = max(L)
if contains(delta(y,X),L): # If former is the subset of L
delete(delta(y,X), L) # Remove lengths from L
X += list(y) # assert that this y is one of the fixed points, X
X = sorted(X) # To maintain order
print(X)
place(L,X) # Recursive call of the function to redo the upper part
# If none of the if statements match the condition, continue
X.remove(y) # If the code reaches down here, it means the assumption that
# y is one of the points is wrong. Thus undo
L += delta(y,X) # undo L
L = sorted(L) # To maintain order
# Do the same thing except this time it's (width-y)
elif contains(delta(width-y,X),L):
delete(delta(width-y,X), L)
X += list(width - y)
X = sorted(X)
place(L,X)
X.remove(width-y)
L += delta(y,X)
L = sorted(L)
L = [2,2,3,3,4,5,6,7,8,10]
X = partialDigest(L)
print(X)

How to write a function that copies all of the elements of a list except the largest value into another list? Python 3.2

I'm trying to answer this question on a practice test:
Write a function, def eliminate(x, y), that copies all the elements of the list x except the largest value into the list y.
The best thing I could come up with is:
def eliminate(x, y):
print(x)
y = x
big = max(y)
y.remove(big)
print(y)
def main():
x = [1, 3, 5, 6, 7, 9]
y = [0]
eliminate(x, y)
main()
I don't think that'll cut it if a question like that comes up on my final, and I'm pretty sure I shouldn't be writing a main function with it, just the eliminate one. So how would I answer this? (keep in mind this is an introductory course, I shouldn't be using more advanced coding)
I'd probably do this:
def eliminate(x, y):
largest = max(x)
y[:] = [elem for elem in x if elem != largest]
This fills y with all the elements in x except whichever is largest. For example:
>>> x = [1,2,3]
>>> y = []
>>> eliminate(x, y)
>>> y
[1, 2]
>>> x = [7,10,10,3,4]
>>> eliminate(x, y)
>>> y
[7, 3, 4]
This assumes that by "copies" the question is asking for the contents of y to be replaced. If the non-maximal elements of x are to be appended to y, you could use y.extend instead.
Note that your version doesn't handle the case where there are multiple elements with the maximum value (e.g. [1,2,2]) -- .remove() only removes one of the arguments, not all of them.
In order to find the largest number in a list you will need to iterate over that list and keep trace of the largest element along the way. There are several ways to achieve this.
So this code answers the question:
y.extend([n for n in x if n != max(x)])
but i'm worried it might not solve your problem, which is learning how and why this works. Here is that code expanded into a very straight forward way that just uses for loops and if statments.
def trasfer_all_but_largest(transfer_from_list, transfer_to_list):
current_index = 0
index_of_current_largest_element = 0
largest_element_so_far = None
for element in transfer_from_list:
if current_index == 0:
largest_element_so_far = element
else:
if element > largest_element_so_far:
largest_element_so_far = element
index_of_current_largest_element = current_index
current_index = current_index + 1
index_of_largest_element = index_of_current_largest_element
current_index = 0 # reset our index counter
for element in transfer_from_list:
if current_index == index_of_largest_element:
continue # continue means keep going through the list
else:
transfer_to_list = transfer_to_list + [element]
current_index = current_index + 1
return transfer_to_list
list_with_large_number = [1, 2, 100000]
list_were_transfering_to = [40, 50]
answer_list = trasfer_all_but_largest(list_with_large_number, list_were_transfering_to)
print(answer_list)

Categories