Suppose I have the following lists:
x = [0.5, 0.9, 0.1, 0.3, 0.6]
y = [0.4, 0.3, 0.6, 0.1, 0.9]
I want to write a function that iterates through the list and compares each value in order.
def compare_numbers(prob,thresh): output = [] for x, y in zip(prob, thresh): if x >= y: output.append(1) else: output.append(0) return output
compare_numbers(x,y)
This gives me Type Error: 'float' object is not iterable'
Why is this?
I would expect the output to look like this:
[1, 1, 0, 1, 0]
Is there anyway I could write this function such that if the "threshold" value was only one digit it would still work?
My current code to make the latter function is:
def compare_numbers(prob, thresh): output = [] for n in prob: if n >= thresh: output.append(1) else: output.append(0) return output
compare_numbers(x,y)
Yet this returns the Type Error: TypeError: '>=' not supported between instances of 'int' and 'list'
when thresh is a list.
CodePudding user response:
Psychic debugging:
Your first function is passed a
float
for eitherprob
orthresh
, but the code assumes both inputs arelist
(really, any iterable) of numbers.Your second function has the opposite problem, it assumes
thresh
is a single scalar value (e.g.float
), but you passed it as alist
.
Seems like confusion on your part; you passed the arguments for the first function to the second and vice-versa. I can't say exactly how it went wrong, because you didn't show enough information about how you called the functions, but the tracebacks make the ultimate problem obvious.
If you want a function that accepts either of:
- A single
float
- A
list
with some number of floats (that can be extended to matchprob
if it's too short)
for thresh
, you could do:
from itertools import cycle
def compare_numbers(prob,thresh):
try:
iter(thresh) # Check if it's iterable, so we can wrap if it's not
except TypeError:
thresh = (thresh,) # Convert float to one-tuple of float for compatibility later
output = []
for x, y in zip(prob, cycle(thresh)):
if x >= y:
output.append(1)
else:
output.append(0)
return output
The loop itself could also be one-lined to just:
return [int(x >= y) for x, y in zip(prob, cycle(thresh)]
or:
return [1 if x >= y else 0 for x, y in zip(prob, cycle(thresh)]
for simplicity and a small performance bump.
CodePudding user response:
The problem is that you are comparing the value n from prob with the entire list thresh. What you need to do is to also iterate over thresh. Here is a small fix that will allow your code to work:
def compare_numbers(prob, thresh):
output = []
for n in range(len(prob)):
if prob[n] >= thresh[n]:
output.append(1)
else:
output.append(0)
return output
CodePudding user response:
This should work whether thresh
is a list, tuple or a single value:
def compare_numbers(prob,thresh):
if isinstance(thresh, (list, tuple)):
return [int(x >= y) for x,y in zip(prob,thresh)]
else:
return list(map(lambda x: int(x >= thresh), prob))
print(compare_numbers(x,y))
Or:
def compare_numbers(prob,thresh):
return [int(x >= y) for x,y in zip(prob, thresh)] if isinstance(thresh, (list, tuple)) else [int(x >= thresh) for x in prob]
Output:
# list
x = [0.5, 0.9, 0.1, 0.3, 0.6]
y = [0.4, 0.3, 0.6, 0.1, 0.9]
[1, 1, 0, 1, 0]
# int or float
x = [0.5, 0.9, 0.1, 0.3, 0.6]
y = 0.4
[1, 1, 0, 0, 1]