For example say i have the below list and I want to print out only even #s - i want to use lambda.
My question is do i need to have a else in the if ?
_l = [1, 2, 3, 4, 5, 6]
_l2 = list(map(lambda x: x if x % 2 == 0 else "", _l))
I dont want to use the else ...
That's not an if statement anyway, it's a conditional expression. Python conditional expressions are of the form z if x else y, so yes, you do need the else.
However, it looks like you're really just trying to filter the list, so if you want an one-liner, use a list comprehension with an if fragment:
l2 = [x for x in l if x % 2 == 0]
If you struggle with list comprehension maybe just use filter. Might be easier to grasp if you insist on using lambda and want to write functional programming.
_l2 = list(filter(lambda x: (x % 2 == 0), _l))
Thanks guys - i can def use list comprehension also can use filter - thats what i did (posted in the comment).
I guess what i was really asking is can i have a if statement in lambda without the else ?
So for the above yes i used filter - fundamentally :
_l = [x for x in range(0,100,1)]
_l2 = list (map ( lambda x:x if x%2 == 0 else None, _l ) )
_l3 = list ( filter (None, _l2) )
But my question is Do i need to have the else ?
thanks
Related
I am experimenting with how to condense if statements within my code. I have a project I am working on that has several "if" statements (too many to keep track of) and want to figure out a way to condense them. Obviously this involves a for loop, but I am having trouble adding additional operations within this loop.
I came up with the following working example to demonstrate my issue:
num=6
if_options = [num==5, num==6]
for i in range(len(if_options)):
if if_options[i]:
print(num)
I want to add an additional piece to the code. This additional piece will execute an operation within the if statement. See following non-working example as a framework for what I am trying to accomplish:
num=6
if_options = [num==5, num==6]
operations = [num=num+1, num=num-1]
for i in range(len(if_options)):
if if_options[i]:
operations[i]
print(num)
For whatever reason, it will not execute the operation portion of the code and fails with a syntax error. It does not let me declare the command "num=num+1" (without quotes) within a list, however this declaration is necessary for executing the command. I feel like I am missing one little thing and it should be an easy fix. Thank you in advance!!
The problem here is that the operations are evaluated when you create the list of them. You want to write them as strings, and then eval/exec them in the loop. I will assume you also want the conditions evaluated in the loop.
num = 6
if_options = ['num==5', 'num==6']
operations = ['num=num+1', 'num=num-1']
for i in range(len(if_options)):
if eval(if_options[i]):
exec(operations[i])
print(num)
why not functions?
def check(inp):
#you can do some logic and type checking here
return type(inp)==int # for example, or return arguments to pass to the operatiins
def operation(inp2):
if inp2: # check if true or not empty, as an example
#do some operations
# and then you do something like
for x in input_of_things:
operation( check( x ) )
You could use lambda expressions too.
num = 6
if_option_checks = [lambda x: x == 5, lambda x: x == 6]
operations = [lambda x: x + 1, lambda x: x - 1]
for check, operation in zip(if_option_checks, operations):
if check(num):
num = operation(num)
Or you could use dictionaries and lambda expressions
num = 6
if_option_checks = {"add": lambda x: x == 5, "sub": lambda x: x == 6}
operations = {"add": lambda x: x + 1, "sub": lambda x: x - 1}
for key, check in if_option_checks.items():
if check(num):
num = operations[key](num)
Perhaps a switch statement structure could help.
First define a switch function:
def switch(v): yield lambda *c: v in c
Then use is in a one-iteration for loop that yields a case function for the switch value:
for case in switch(num):
if case(5):
num = num + 1
break
if case(6):
num = num - 1
break
...
Here's a piece of code from this question, it's an alternative to a switch statement in Python.
result = {
'a': lambda x: x * 5,
'b': lambda x: x + 7,
'c': lambda x: x - 2
}[value](x)
I'm new to Python and I don't understand what it's doing. So I get that the first part is variable assignment - but what does [value](x) do?
The part between the braces {} defines a dictionary, with keys of 'a', 'b' and 'c'. The values for those keys are lambdas, which are anonymous functions (functions with no name). Each lambda defines a mapping of x to a function of x, with three different mappings, one for each key.
'[value]' looks up value in the dictionary. So if value = 'b', it will return lambda x: x + 7. This x is not related to the x in (x). The lambdas could have been defined as lambda y: y + 7 for example.
'(x)' then applies that lambda to whatever the value of x is.
So if value = 'b' and x = 8, the expression above will give 15 as the answer.
It is a convoluted way to replicate a switch statement. A cleaner way would be to define a helper function that will let you use a more straightfoward expression of what's going on:
def switch(v):yield lambda *c: v in c
Which you could use like this to get the equivalent result:
for case in switch(value):
if case('a'): result = x + 5
elif case('b'): result = x + 7
elif case('c'): result = x - 2
That is a very simple example which does little more than make the code more legible. When you have more complex or varied things to do in each case, then this switch pattern becomes a lot more valuable. You can also use it in a more C-Like style:
for case in switch(letter):
if case('a','A'):
y = complexCalculation(12,4)
result = y + 5
print(y)
break
if case('b','c','d'):
z = factorial(y) **2
result = z + 5
print(z)
break
else: # otherwise (all other cases)
print("invalid value provided")
The goal of this post is to put multiple print functions throughout a list comprehension to visually understand what's happening within.
Important notes:
This should not be used for anything other than educational purposes and trying to understand code.
If you are using Python 2.x, you need to add a future import (it's in the code I pasted) or else print won't work. Only functions work in list comprehension. Print in 2.x does not operate as a function. Or...just switch to Python 3.x.
This was the original question:
## Using future to switch Print to a function
from __future__ import print_function
reg = []
for x in [1,2,3]:
for y in [3,1,4]:
print('looping through',x,'then',y)
if x == y:
print('success',x,y)
reg.append((x,y))
print(reg)
Here's the equivalent list comprehension with no print statements.
from __future__ import print_function
comp = [(x,y) for x in [1,2,3] for y in [3,1,4] if x == y]
print(comp)
So is there any way to put in a bunch of print statements so both code print the same things?
Edit with solution to original question:
Using the methods in the comments - I've figured it out!
So say you want to convert this.
from __future__ import print_function
x = 1
y = 2
z = 1
n = 2
[[a,b,c] for a in range(x+1) for b in range(y+1) for c in range(z+1) if a + b + c != n]
Adding print statements to print each loop, showing if it failed or not.
from __future__ import print_function
x = 1
y = 2
z = 1
n = 2
[
[a,b,c] for a in range(x+1) for b in range(y+1) for c in range(z+1) if
(print('current loop is',a,b,c) or a + b + c != n)
and
(print('condition true at',a,b,c) or True)
]
So really the only thing that was changed was the conditional at the end.
(a + b + c != n)
to
(print('current loop is',a,b,c) or a + b + c != n)
and
(print('condition true at',a,b,c) or True)
Additional Information:
So there's good stuff in the comment section that I think would help others as well. I'm a visual learner so this website was great.
http://treyhunner.com/2015/12/python-list-comprehensions-now-in-color/#colored-comprehension
(credits to Tadhg McDonald-Jensen)
I think you shouldn't running debug code inside list comprehensions, that said, if you wanted to do so, you could wrap your code inside a function like this:
from __future__ import print_function
def foo(x, y):
print('looping through', x, 'then', y)
if x == y:
print('success', x, y)
return (x, y)
comp = [foo(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x == y]
print(comp)
You need to evaluate your print function, but the return value isn't useful since it's always None. You can use and/or to combine it with another expression.
comp = [(x,y) for x in [1,2,3] for y in [3,1,4] if (print('looping through',x,'then',y) or x == y) and (print('success', x, y) or True)]
I really hope you're only doing this for educational purposes, because it's ugly as heck. Just because you can do something doesn't mean you should.
List comprehension was introduced with PEP 202 which states:
It is proposed to allow conditional construction of list literals
using for and if clauses. They would nest in the same way for loops
and if statements nest now.
List comprehension was designed to replace constructs that formed a list using only for loops, if conditionals and .append method once per iteration. Any additional structure is not possible in list comprehensions so unless you stuck your prints into one of the allowed components you cannot add them.
That being said, putting a print statement in the conditional - while technically possible - is highly not recommended.
[a for a in x if print("this is a bad way to test",a)]
I want to make a function that changes each elements in list with lambda function.
a = [1,5,2,4]
def func1(list,func2):
for x in range(len(list)):
list[x] = func2(list[x])
func1(a,lambda x: x>3 and 10 or x)
print a
The result is [1,10,2,10]
This is OK. But I change '10' to '0'
func1(a,lambda x: x>3 and 0 or x)
The result is [1,5,2,4]
Why doesn't the result be [1,0,2,0]?
I'm sorry that I'm poor at English.
The problem you have is that 0 is being evaluated as False which means that using the and-or trick as a conditional expression is failing.
Python 2.5 introduced "proper" conditional expressions of the form:
x = true_value if condition else false_value
So you can replace:
lambda x: x>3 and 0 or x
with:
lambda x: 0 if x > 3 else x
Also, you could use the map function to replace func1 if you're not bothered about updating the list in place:
a = map(lambda x: 0 if x > 3 else x,a)
print a
If you do want to modify the list in place you can use the enumerate function to simplify your code a little:
def func1(list,func2):
for i,x in enumerate(list):
list[i] = func2(x)
bool(0) -> False
bool(10) -> True
a and b or c
is equivalent (nearly, since your case proves it is not) to
b if a else c
So:
a = [1,5,2,4]
def func1(li,func2):
for x,el in enumerate(li):
li[x] = func2(el)
func1(a,lambda x: 0 if x>3 else x)
print a
Remark:
name list for a user's object is not good
use of iterate()
By the way, did you notice that you are changing in a function the value of an object external to the function ?
u = 102
def f(x):
x = 90
print "u==",u
result
u== 102
In your code, a is changed because it is a mutable object
In common case, a function has a return. Yours has not, because you change a mutable object.
x>3 and 0 or x always returns x because 0 is False.
Replace it with:
(x > 3 and [0] or [x])[0]
to get:
func1(a,lambda x: (x>3 and [0] or [x])[0])
Result:
[1, 0, 2, 0]
How it works:
The real return value is put into a single element list.
Any non-empty list is True, so the and or works.
Then use [0] to get the value back out.
You could turn it around:
func1(a,lambda x: x<=3 and x or 0)
(untested)
In Ruby, I'm used to using Enumerable#inject for going through a list or other structure and coming back with some conclusion about it. For example,
[1,3,5,7].inject(true) {|allOdd, n| allOdd && n % 2 == 1}
to determine if every element in the array is odd. What would be the appropriate way to accomplish the same thing in Python?
To determine if every element is odd, I'd use all()
def is_odd(x):
return x%2==1
result = all(is_odd(x) for x in [1,3,5,7])
In general, however, Ruby's inject is most like Python's reduce():
result = reduce(lambda x,y: x and y%2==1, [1,3,5,7], True)
all() is preferred in this case because it will be able to escape the loop once it finds a False-like value, whereas the reduce solution would have to process the entire list to return an answer.
Sounds like reduce in Python or fold(r|l)'?' from Haskell.
reduce(lambda x, y: x and y % == 1, [1, 3, 5])
I think you probably want to use all, which is less general than inject. reduce is the Python equivalent of inject, though.
all(n % 2 == 1 for n in [1, 3, 5, 7])