In general with FOP ( functional oriented programming ) you can put it all in one liner and nest lambdas within one-liners but that is in general bad etiquette, since after 2 nesting function it all becomes quite unreadable.
The best way to approach this kind of issue is to split it up in several stages:
1: splitting string into tuple
:
lst = ['b-3', 'a-2', 'c-4', 'd-2']
res = map( lambda str_x: tuple( str_x.split('-') ) , lst)
2: sorting elements like you wished :
lst = ['b-3', 'a-2', 'c-4', 'd-2']
res = map( lambda str_x: tuple( str_x.split('-') ) , lst)
res = sorted( res, key=lambda x: ( int(x[1]), x[0] ) )
Since we split the string into tuple it will return an map object that will be represented as list of tuples. So now the 3rd step is optional:
3: representing data as you inquired:
lst = ['b-3', 'a-2', 'c-4', 'd-2']
res = map( lambda str_x: tuple( str_x.split('-') ) , lst)
res = sorted( res, key=lambda x: ( int(x[1]), x[0] ) )
res = map( '-'.join, res )
Now have in mind that lambda nesting
could produce a more one-liner solution and that you can actually embed a non discrete nesting type of lambda like follows:
a = ['b-3', 'a-2', 'c-4', 'd-2']
resa = map( lambda x: x.split('-'), a)
resa = map( lambda x: ( int(x[1]),x[0]) , a)
# resa can be written as this, but you must be sure about type you are passing to lambda
resa = map( lambda x: tuple( map( lambda y: int(y) is y.isdigit() else y , x.split('-') ) , a)
But as you can see if contents of list a
arent anything but 2 string types separated by '-'
, lambda
function will raise an error and you will have a bad time figuring what the hell is happening.
So in the end, i would like to show you several ways the 3rd step program could be written:
1:
lst = ['b-3', 'a-2', 'c-4', 'd-2']
res = map( '-'.join,\
sorted(\
map( lambda str_x: tuple( str_x.split('-') ) , lst),\
key=lambda x: ( int(x[1]), x[0] )\
)\
)
2:
lst = ['b-3', 'a-2', 'c-4', 'd-2']
res = map( '-'.join,\
sorted( map( lambda str_x: tuple( str_x.split('-') ) , lst),\
key=lambda x: tuple( reversed( tuple(\
map( lambda y: int(y) if y.isdigit() else y ,x )\
)))\
)\
) # map isn't reversible
3:
res = sorted( lst,\
key=lambda x:\
tuple(reversed(\
tuple( \
map( lambda y: int(y) if y.isdigit() else y , x.split('-') )\
)\
))\
)
So you can see how this all can get very complicated and incomprehensible. When reading my own or someone else's code i often love to see this version:
res = map( lambda str_x: tuple( str_x.split('-') ) , lst) # splitting string
res = sorted( res, key=lambda x: ( int(x[1]), x[0] ) ) # sorting for each element of splitted string
res = map( '-'.join, res ) # rejoining string
That is all from me. Have fun. I've tested all code in py 3.6
.
PS. In general, you have 2 ways to approach lambda functions
:
mult = lambda x: x*2
mu_add= lambda x: mult(x)+x #calling lambda from lambda
This way is useful for typical FOP,where you have constant data , and you need to manipulate each element of that data. But if you need to resolve list,tuple,string,dict
in lambda
these kind of operations aren't very useful, since if any of those container/wrapper
types is present the data type of elements inside containers becomes questionable. So we would need to go up a level of abstraction and determine how to manipulate data per its type.
mult_i = lambda x: x*2 if isinstance(x,int) else 2 # some ternary operator to make our life easier by putting if statement in lambda
Now you can use another type of lambda
function:
int_str = lambda x: ( lambda y: str(y) )(x)*x # a bit of complex, right?
# let me break it down.
#all this could be written as:
str_i = lambda x: str(x)
int_str = lambda x: str_i(x)*x
## we can separate another function inside function with ()
##because they can exclude interpreter to look at it first, then do the multiplication
# ( lambda x: str(x)) with this we've separated it as new definition of function
# ( lambda x: str(x) )(i) we called it and passed it i as argument.
Some people call this type of syntax as nested lambdas, i call it indiscreet since you can see all.
And you can use recursive lambda assignment:
def rec_lambda( data, *arg_lambda ):
# filtering all parts of lambda functions parsed as arguments
arg_lambda = [ x for x in arg_lambda if type(x).__name__ == 'function' ]
# implementing first function in line
data = arg_lambda[0](data)
if arg_lambda[1:]: # if there are still elements in arg_lambda
return rec_lambda( data, *arg_lambda[1:] ) #call rec_lambda
else: # if arg_lambda is empty or []
return data # returns data
#where you can use it like this
a = rec_lambda( 'a', lambda x: x*2, str.upper, lambda x: (x,x), '-'.join)
>>> 'AA-AA'