Multiple conditional statements for list comprehension Python - python

I have a list with elements that I want to do operations on with 2 conditions.
One condition is to multiply a norm function by -1 if the element is negative or leaving the norm function positive if the element is positive.
The list of values looks like this:
print(values)
-97476.70633454417
-93170.30642401175
-89901.82679086612
-87187.62533194348
-87269.09594982903
-85513.31676486236
-83545.26529198853
-82411.91255123452
-81620.01849452594
As you can see they are all negative (in this experiment).
The code looks like this:
norm_BIC = [(-1.0) * float(i)/max(values) for i in values if i < 0 or float(i)/max(values) for i in values if i > 0]
If I run the code before the or statement it works:
norm_BIC = [(-1.0) * float(i)/max(values) for i in values if i < 0]
Which means it's everything else following that doesn't work because I get an empty list for norm_BIC when running after the or.
How do I fix this condition?

It seems that you are simply filtering out the negative values and turning them positive. The abs function takes the absolute value, turning your inputs positive.
would
norm_BIC = [ abs(float(i))/max(values) for i in values]
not fix your problem?

To achieve "this or that" in a list comprehension you need to use an if expression. This allows you to add an else clause as expected —
values = [
-97476.70633454417,
-93170.30642401175,
-89901.82679086612,
-87187.62533194348,
-87269.09594982903,
-85513.31676486236,
-83545.26529198853,
-82411.91255123452,
-81620.01849452594,
]
norm_BIC = [(-1.0) * float(i)/max(values) if i < 0 else float(i)/max(values) for i in values if i > 0]
The syntax here isn't list-comprehension specific, compare to this if expression —
a = 10 if b < 10 else 20
Running your example values without that final if i.e.
norm_BIC = [(-1.0) * float(i)/max(values) if i < 0 else float(i)/max(values) for i in values]
I get the following output.
[-1.1942744945724522,
-1.1415129295794078,
-1.1014678561595233,
-1.0682137414339221,
-1.0692119109931586,
-1.0477002865491576,
-1.0235879240531134,
-1.0097022038381638,
-1.0]
If you just want to ensure the result of your calculation is positive you could use the built-in abs() function.
norm_BIC = [abs(float(i)/max(values)) for i in values]

You should use an else clause:
norm_BIC = [(-1.0) * float(i)/max(values) if i < 0 else float(i)/max(values) for i in values]

Related

Find index of first element with condition in numpy array in python

I'm trying find the index of the first element bigger than a threshold, like this:
index = 0
while timeStamps[index] < self.stopCount and index < len(timeStamps):
index += 1
Can this be done in a one-liner? I found:
index = next((x for x in timeStamps if x <= self.stopCount), 0)
I'm not sure what this expression does and it seems to return 0 always... Could somebody point out the error and explain the expression?
Another option is to use np.argmax (see this post for details). So your code would become something like
(timeStamps > self.stopCount).argmax()
the caveat is that if the condition is never satisfied the argmax will return 0.
I would do it this way:
import numpy as np
threshold = 20
sample_array = np.array([10,11,12,13,21,200,1,2])
idx = np.array([np.where(sample_array > threshold)]).min()
print(idx)
#4
this one liner will work
sample_array = np.array([10,11,12,13,21,200,1,2])
# oneliner
print(sum(np.cumsum(arr>threshold)==0))
np.cumsum(sample_array>threshold)==0) will have value 0 until element is bigger than threshold

Python sorting arrays to get two digit values

I have an array A = [1 - 100] and I need to find the sum of all the two digit values in this array. How would I approach this? I have tried :
def solution(A):
A =array[0-100])
while A > 9 & A < 99
total = sum(A)
print "%s" % total
)
Is there a function that given an array consisting of N integers returns the sum of all two digit numbers i.e A = [1,1000,80, -91] the function should return -11(as the two are 80 and -91). not a range, multiple array
You can use a list comprehension and check if the length of the string-format is equal to 2, like so:
sum([x if len(str(x))==2 else 0 for x in xrange(1,101)])
Use the keyword and rather than the bitwise &.
Edit: a fuller answer, as that's not the only thing wrong:
def solution():
A = range(101)
total = sum([a for a in A if 9 < a <= 99])
print total
This uses list comprehension and chained inequalities, so is pretty 'pythonic'.
There is tons of errors in your code, please next time before posting,spend some time try to figure it out yourself and be sure that your code at lest doesn't contain any obvious syntax error.
By array, I assume you're talking about a list. And change it to range(101) for every number from 0 to 100
def solution(A):
return sum([x for x in range(A) if len(str(abs(x))) == 2])
print(solution(101))
As a side note, use and instead of & since that's a bitwise-or sign.
Here are a couple of ways to go about the problem, the first is most similar to the approach you appear to be trying:
def solution1(array):
total = 0
for a in array:
if 9 < a < 100:
total += a
return total
print(solution1(range(101)))
And here's a more compact solution using a comprehension (actually, a generator expression):
def solution2(array):
return sum(a for a in array if 9 < a < 100)
print(solution2(range(101)))
Note that in your original you're confusing loops and conditionals.

Python - If array is in range of other array

Meaning "if each item is within range of other item with the same index".
price = [1, 2]
budget = [5, 7]
This works:
if price[0] in range(budget[0]) and price[1] in range(budget[1]):
affordable = True
I figure there's some way to just reference the whole array though. Like so: if price in budget:
You could use:
if all(x in range(y) for x,y in zip(price,budget)):
affordable = True
This will create tuples of price[i],budget[i] and then for each of these tuples we check that price[i] is in range(budget[i]). Nevertheless, you can optimize this further to:
if all(0 <= x < y for x,y in zip(price,budget)):
affordable = True
Note that this makes the assumption that prices are all integers. If you however use x in range(y) it will fail if x is not an integer. So 0.7 in range(10) would fail whereas our second approach will succeed (but it depends of course on what you want).
Assuming that both prices and budgets must be non-negative, using in range seems to be over-complicating things. Instead, you could just use the < operator.
Regardless of whether you use < or in range, it seems like the easiest approach would be to zip both lists and apply the condition on the pairs:
if (all([x[0] >= x[1] for x in zip(budget, price)])):
affordable = True

How to use map lambda of python to make a element to a certain number?

I have a numpy.array called p2De. The first row has multiple elements may larger than 1. I want to set the elements which smaller than 1 to 1. Following is my code, but shows error... why? How to fix it?
bounde=1
p2De[:0]=map(lambda x:bounde if (x < bounde),p2Di[:0])
File "C:\Users\wange\workspace\cathode\src\diffusion.py", line 86
p2De[:0]=map(lambda x:bounde if (x < bounde),p2Di[:0])
^
SyntaxError: invalid syntax
You need to specify an else for your lambda function :
lambda x:bounde if (x < bounde) else #stuff
It should be
lambda x:bounde if (x < bounde) else x
You can also use list comprehension, which is more readable. Also, I would use the max builtin function instead of your lambda:
p2De[:0] = [max(x, bounde) for x in p2Di[:0]]
As others have noted, the syntax problem is in the lambda.
I don't think you want p2De[:0] - that's an empty array. p2De[0] is the 1st row. p2De[0,:] is the same, and makes it clear to the human readers that you have selected the 1st row of a 2d array.
The use of a map or comprehension works, but they don't offer much of an advantage, if any, over a simple loop (since you don't need to replace all of the values):
for i,v in enumerate(p2De[0,:]):
if v<1:
p2De[0,i] = 1
But none of these iterations is good numpy practice. You should try to think in terms of vector operations. A common practice is to use a boolean mask (or indexing) to select the values that should be changed:
I = p2De[0,:]<1 # boolean vector
p2De[0, I] = 1
p2De[0,p2De[0,:]<1]=1 # or one line form
There is also a numpy function that applies limits like this, np.maximum:
p2De[0,:] = np.maximum(p2De[0,:], 1)
np.clip applies both minimum and maximum bounds:
p2De[0,:] = np.clip(p2De[0,:], minbd, maxbd)
np.clip(p2De[0,:], minbd, maxbd, p2De[0,:]) # alt calling method
The Python(3) bosses encourage us to use functions and comprehensions over maps and lambdas. For example if plist was a list like your p2De[0,:] row:
def clip(x):
return 1 if x<1 else x
plist = [clip(x) for x in plist]
plist = [min(x, 1) for x in plist] # using a builtin for this simple case
say if you have a list a, you can do something like this:
a=[2,3,1,7,0,0,8]
bounde=1
b = map(lambda n: n if n > bounde else bounde,a)
print b

min() arg is an empty sequence

I'm trying to find minimum element in matrix row, but there are two conditions:
1) it must be > 0
2) and this point must be not visited(is_visited[k] is False)
I'm trying to do next:
min(x for x in matr_sum[i] if x > 0 if is_visited[k] is False )
But there is an error: min() arg is an empty sequence
The full block of code:
for k in range(4):
if matr_sum[i][k] == min(x for x in matr_sum[i] if x > 0 if is_visited[k] is False ) and i!=k:
return k
How to resolve it? Or should I write my min() function? Because it works with one condition:
min(x for x in matr_sum[i] if x > 0)
But with two conditions, it doesn't work.
If you want to avoid this ValueError in general, you can set a default argument to min(), that will be returned in case of an empty list. See described here.
min([], default="EMPTY")
# returns EMPTY
Note that this only works in Python 3.4+
There is no problem with the syntax. It's certainly unusual to have two if clauses, but it's allowed. Consider:
print(min(x for x in range(1,300) if x % 3 == 0 if x % 5 == 0))
Output:
15
However:
print(min(x for x in range(1,300) if x % 2 != 0 if x % 2 != 1))
Output:
ValueError: min() arg is an empty sequence
There are no integers that are both odd and even, so there are no values for min to see, so it throws an exception.
I deduce that in your code, there are no values that pass both conditions. Python doesn't allow you to compute "the minimum of no values", mainly because it makes no sense.
You have to decide what you want to do in the case where there is no minimum because there are no values greater than 0. For example, if you don't want to return k in that case then I might re-write your code something like this:
for k in range(4):
if k != i and is_visited[k] is False:
if matr_sum[i][k] > 0 and matr_sum[i][k] == min(x for x in matr_sum[i] if x > 0):
return k
It might not be obvious why this helps, but assuming matr_sum[i] is a list or similar, then once we know matr_sum[i][k] > 0 then we know the generator passed to min isn't empty, so we won't get an exception. Whereas if matr_sum[i][k] <= 0, then it certainly isn't equal to the smallest positive value, so there's no need to compute the min at all. Another way to write that would be:
if matr_sum[i][k] > 0 and not any(0 < x < matr_sum[i][k] for x in matr_sum[i])
Actually, I'd normally write if not is_visited[k], but I leave it as is False since I don't know whether changing it would change the behaviour of your code.
Try this - it creates the list of x values xs and then only tries to find the min if xs is non-empty. You may need to add some logic to handle the case that xs is empty, depending on what your code is doing.
for k in range(4):
if is_visited[k] is False and i != k:
xs = [x for x in matr_sum[i] if x > 0]
if xs and matr_sum[i][k] == min(xs):
return k
Just use and operation for concatenate tow if statement :
min(x for x in matr_sum[i] if x > 0 and if is_visited[k] is False and i!=k)

Categories

Resources