Using list comprehension with over 4 conditions - python

I have a list of lists. Each sub-list contains two integer elements. I would like to multiply each of these elements by 1.2 and if they are positive and bigger then a certain number, change them to be that certain number. same thing if they are smaller.
The multiplication bit I achieved using list comprehension. With these extra conditions, I'm getting a little lost - to me, it seems overly complicated and even non pythonic. I was wondering if I can get some opinions.
The multiplication bit I achieved using list comprehension. With these extra conditions, I'm getting a little lost - to me, it seems overly complicated and even non pythonic. I have a rough idea on how to put all the conditions in the list comprehension, but when I started implementing them I got confused. I was wondering if I can get some opinions.
MAX_VOL = 32767 # audio data is the list of lists
MIN_VOL = -32767
audio_list = [[int(x*1.2), int(y*1.2)] for x, y in audio_data]
# My idea was something like:
audio_list = [[int(x*1.2), int(y*1.2) if x > MAX_VOL x == MAX VOL if x < MIN_VOL....] for x, y in audio_data]
Firstly, I'm pretty sure there is a syntax issue. But, for each number, I have to check if its positive or negative, then, if it is bigger or smaller then max/min volume. So, is this possible using list comprehension? Is it efficient and pythonic?
Thank you so much!

Use min and max:
MAX_VOL = 32767 # audio data is the list of lists
MIN_VOL = -32767
audio_list = [[int(max(MIN_VOL, min(MAX_VOL, x*1.2))), int(max(MIN_VOL, min(MAX_VOL, y*1.2)))] for x, y in audio_data]
And since these are long expressions, use a function, too:
def clip(s):
return int(max(MIN_VOL, min(MAX_VOL, s)))
audio_list = [[clip(x*1.2)), clip(y*1.2)] for x, y in audio_data]

Define a bounding function that doesn't let the value exceed the max or min volume. Then you can still use list comprehension.
MAX_VOL = 32767 # audio data is the list of lists
MIN_VOL = -32767
# Ensure volume does not exceed limits.
def bounded(val):
if val > MAX_VOL:
return MAX_VOL
elif val < MIN_VOL:
return MIN_VOL
return val
audio_list = [[bounded(int(x*1.2)), bounded(int(y*1.2))] for x, y in audio_data]

If a list comprehension is too complex, then don't use it. You should try and make your solution easy for someone else to understand and for you to understand if you come back to it in a year.
for x,y in audio_data:
if x > MAX_VOL:
foo = int(x*1.2)
bar = int(y*1.2)
if x == MAX_VOL:
...

Related

A function that calculates the average of a list and returns the elements that are greater than the mathematical average of the entire list

I'm trying to make a function that would calculate the average of a given list then returns all the elements within that list which are greater than the mathematical average of that list. Example:
if the given list is [1,2,3,4,5,6], the average would be 3.5. So the function should print out the numbers (4,5,6).
I've gotten as far as adding all the numbers up within the list but no matter what I do, I can't figure out how to get the average or get it to print out the numbers that are greater than the mathematical average.
This is what i have so far to add all the elements of any given list:
def accum2(seq):
total = 0
for x in seq:
total += x
return total
print (accum2([1,2,3,4,5,6]))
The expected result of print (accum2([1,2,3,4,5,6])) should be (4,5,6) but so far I just get an answer where it just adds up all the number in the given list.
Any help is greatly appreciated and thank you in advance.
The simplest way to get the average value of a list of numeric values is to use the methods:
average = sum(seq) / len(seq)
From there just use a conditional statement (you might have to sort the list first, if it is unsorted). From there you should be able to build a new list using the built in list methods.
heres some simple code which should work.
I have added comments.
originallist = [1,2,3,4,5,6] #This is your original list
outputlist = [] #This is the list which you can add correct values to
x = sum(originallist) / len(originallist) #This effectively finds you the average
for item in originallist: #Checks which items are greater than average
if item > x:
outputlist.append(item) #If greater, add to the final list
print(outputlist)
There are many correct ways to do this, one of which is shown below (Python 3).
lst = [1,2,3,4,5,6]
avg = sum(lst)/len(lst)
res = list(filter(lambda x: x > avg, lst))
print(res)
will produce
[4,5,6].
I prefer this approach because it's less verbose than loops and also can be more easily translated to a framework like Pandas or an eventual parallel implementation if such a need arises in the future (e.g., using Spark).
This is the extended version of your work:
def accum2(seq):
total = 0
for x in seq:
total += x
L=[]
for x in seq:
if x>total/len(seq):
L.append(x)
return L
print (accum2([1,2,3,4,5,6]))
But you could simply the previous one in this code:
def accum2(seq):
return [x for x in seq if x>(sum(y for y in seq)/len(seq))]
print (accum2([1,2,3,4,5,6]))

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

Python: divide elements of a list based on a condition

I am trying to find the LCM of first 20 natural numbers (Project Euler question 5). For that, my algorithm is:
have numbers 1 to 20 in a list
Divide only those elements of the list that are divisible by i where i is in the range (2-20).
Whatever numbers are left in the list, multiply them and that will be the lcm.
This is the naivest algorithm which we actually used to calculate lcm in school for the first time.
Now, I donot know how to divide the elements of the list based on the condition.
I have tried:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for x in a:
if(x%2==0):
x=x/2
This does not seem to work.
I also tried:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
a1=[if(x%2==0): x/2 for x in a]
the above with both with and without ":" after the if condition. This does not work. I have the following questions:
a. Why isn't the first loop working correctly?
b. Can someone tell me how I can do this?
c. Will my algorithm work correctly?
a. Why isn't the first loop working correctly?
For the same reason as:
Foreach in Python not working as expected
b. Can someone tell me how I can do this?
You can do either:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for i, x in enumerate(a):
if x%2==0:
a[i]=x/2
Or:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
a1=[x/2 if x%2==0 else x for x in a]
c. Will my algorithm work correctly?
I don't think so. You'll end up dividing everyone by itself and the result will always be 1.
But there are other questions here in SO that have simple answers, like:
find least common multiple of numbers 1-20
a) Why is this loop not working correctly?
As #jose-ricardo-bustos-m indicates, the x is not a reference, is a local copy to each element of the array a, and cannot modify the array in the for loop. You can use, instead:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for i,x in enumerate(a): #used to provide a value, and an index
if(x%2==0):
a[i]=x/2
b) Can someone tell me how I can do this?
You can try to use the ternary if operator and list comprehension:
a = [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
b = [x/2 if x%2==0 else x for x in a]
c) Will my algorithm work correctly
You have to keep track of the numbers you have already used, and you might need to divide by the same number more than once. But if you do that, and keep dividing by the same number _until the resulting list is equal to the previous one, and then move to the next, you can later multiply all numbers used, times the remainder of the list (but if you go to the max number in the list, the remaining list will contain just 1's).
def f(l,n): # divides items in a which are divisible by n, or leaves them
return [x/n if x%n==0 else x for x in l]
lcm = 1
a=[2,3,4,5,6,7]
# we go from the smallest to the largest number in your list
for i in range(2,max(a)+1):
repeat_next_time = True
while repeat_next_time:
b = f(a,i)
if a != b:
print('Using %s as a factor' % i)
a = b
lcm *= i
# print(a) # to get the status of the a list
else:
repeat_next_time = False
# finally, for numbers which might have not been divided yet,
# multiply the lcm by all of the remaining items
lcm *= reduce(lambda x,y: x*y, a)
It works even if there are common divisors, or repeated numbers in the list. Try, for instance, with a = [2,2,2], or a = [2,3,6], or a = [8,7,4,7].
a) the variable x takes the value of the list a , but not modified, it is not a reference of list, the following code does what you want:
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
for i in range(len(a)):
if(a[i]%2==0):
a[i]=a[i]/2
b) y C)
a=[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
def f(x):
if(x%2==0):
return x/2
return x
a1=[f(x) for x in a]
Whatever numbers are left in the list, multiply them and that will be the lcm.
reduce(lambda x, y: x*y, a1)

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

Categories

Resources