Explain basic lambda function and sort [duplicate] - python

This question already has answers here:
Syntax behind sorted(key=lambda: ...) [duplicate]
(10 answers)
Closed 6 years ago.
I have just finished my code for a school project, but have used one line of code from stack overflow that is slightly more advanced than the knowledge that's in my "skill comfort zone".
I do understand what it does, why it exists, etc.. But still cannot convert it into "human syntax" for my individual report. Could anyone give me a bit of their time and explain, as precisely as possible, the underlying mechanism in this line of code? Thanks in advance!
sites.sort(key = lambda x: x[0])
The role it has within my program is sorting a dictionary by the integers in its first column, from smallest to biggest.
Need to demonstrate that I fully understand this line of code, which I frankly do not.
Thanks!

A lambda function is basically like any other function, with some restrictions. It can only be one line, and it must be an expression. That expression is evaluated when the lambda function is called and the result of that expression is returned.
sites.sort(key = lambda x: x[0])
is the same as
def f(x):
return x[0]
sites.sort(key = f)
In this case, the lambda function is passed to the sort method as a key function. These are used in sorting to sort things based on something other than their value. Each element e of sites is passed to the key function, and then they are sorted based on f(e) or e[0] rather than the value of e.

When calling sort on an object, Python passes each of the elements contained inside that object to the function you specify as the key parameter.
A lambda function can be dissected in the following parts:
lambda <args>: <what to do with args>
In your lambda function you have a single arg x as the <args>, and your <what to do with args> is to get the zero element of it.
That element x[0] is going to be used in the comparisons sort performs.
In your example, sites must contain elements that themselves contain elements, for example, nested lists: l = [[1, 2, 3], [0, 1, 2, 3]].
Using this example, Python is first going to pass [1, 2, 3] to the lambda as the value of x and the lambda function is going to return x[0] == 1, then it will pass [0, 1, 2, 3] to it and get back x[0] == 0. These values are used during sorting to get the ordering as you require.

Related

Finding the most frequent element in a list in python explanation? [duplicate]

This question already has answers here:
python max function using 'key' and lambda expression
(6 answers)
Closed 1 year ago.
so pretty straight through idea, just want to find the most frequent element but I am just lost on exactly what is happening in this small code snippet. I like how this code doesn't import anything, just simply uses the built-ins. But I dont understand exactly how it works.
Here it is:
def most_frequent(List):
return max(set(List), key = List.count)
w3schools defines the python max() as doing the following:
The max() function returns the item with the highest value, or the
item with the highest value in an iterable. If the values are strings,
an alphabetically comparison is done.
Makes sense so far, so if we have a list like so a_list = [3,2,5,1], then max(a_list) gives us 5. Okay, simple enough.
But in our function why is set being used here? I understand set is a built-in data structure that ensures all data inside it to be unique. And what is key? why are there two parameters here inside like this inside the max()?
I've never seen anything like this before. Running something like max(4,2,6,3,2) makes sense but putting the data structure set to enclose the list and assigning something called key and calling count on the list? What in the world is going on here? Can someone please break this down like I am five and explain how we are able to use the max() like this when the definition is just to find the highest value? What is set and key doing here? Is it like a hashtable?
Quite lost here would truly appreciate the help.
Thank you
The max documentation states that key is an ordering function, the method gives a new value for each item of the iterable , which will be used for ordering
Without key : natural order
max([4, 3, 5, 6])
4, 3, 5, 6 << values used for finding the max
^
With key : order if values given by the key
max([ 4, 3, 5, 6], key=lambda x: -x)
-4, -3, -5, -6 << values used for finding the max
^
Your case, the list.count, that telles that 2 occurs 2, and that is more than the ones
l =[4, 2, 6, 3, 2]
max([4, 2, 6, 3], key=lambda x: l.count(x))
1 2 1 1 << values used for max, regarding the
^

How to sort a list with sort function in python with less time complexity?

I want to sort this list a = [31415926535897932384626433832795, 1, 3, 10, 3, 5]. To reduce time complexity I want to first check whether the 2 elements are of same length or not. If both are of not same length I will swap them according to their length otherwise I will check which number is bigger and swap them. I want to implement this using .sort() function which have a parameter called key. I can use a.sort(key=len) but it will only work for the test cases with different length inputs. Please help me regarding this.
When you are using sort() in Python, you can provide a function or anonymous (lambda) function to it as a basis for sorting.
In this case, you can use lambda x where x are the elements in a.
Subsequently, providing a tuple as a return result in the function allows the sort to prioritize in sorting, thus what you need is this:
a.sort(key=lambda x: (len(str(x)), x))
In the above code, a sorts first by len(str(x)) then by the value of x
Edit: Added explanation

creating a dictionary with anonymous functions in Python [duplicate]

This question already has answers here:
What do lambda function closures capture?
(7 answers)
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 3 years ago.
I have a vector with some parameters and I would like to create a dictionary of anonymous (lambda) functions in Python3.
The goal of this is to create a callable function that gives values equal to the sum of these functions with the same argument.
I am struggling even to create a dictionary with the original lambda function objects and get them to behave consistently. I use the following code:
import numpy as np
a = np.linspace(0,2.0,10)
func = {}
for i,val in enumerate(a):
print(i)
func['f{}'.format(i)] = lambda x: x**val
print(func['f0'](0.5))
print(func['f1'](0.5))
print(func['f2'](0.5))
print(func['f3'](0.5))
The output of the final print statements gives the same value, whereas I would like it to give the values corresponding to x**val with the value of val coming from the originally constructed array a.
I guess what's happening is that the lambda functions always reference the "current" value of val, which, after the loop is executed is always the last value in the array? This makes sense because the output is:
0
1
2
3
4
5
6
7
8
9
0.25
0.25
0.25
0.25
The output makes sense because it is the result of 0.5**2.0 and the exponent is the last value that val takes on in the loop.
I don't really understand this because I would have thought val would go out of scope after the loop is run, but I'm assuming this is part of the "magic" of lambda functions in that they will keep variables that they need to compute the function in scope for longer.
I guess what I need to do is to insert the "literal" value of val at that point into the lambda function, but I've never done that and don't know how.
I would like to know how to properly insert the literal value of val into the lambda functions constructed at each iteration of the loop. I would also like to know if there is a better way to accomplish what I need to.
EDIT: it has been suggested that this question is a duplicate. I think it is a duplicate of the list comprehension post because the best answer is virtually identical and lambda functions are used.
I think it is not a duplicate of the lexical closures post, although I think it is important that this post was mentioned. That post gives a deeper understanding of the underlying causes for this behavior but the original question specifically states "mindful avoidance of lambda functions," which makes it a bit different. I'm not sure what the purpose of that mindful avoidance is, but the post did teach related lessons on scoping.
The problem with this approach is that val used inside your lambda function is the live variable, outside. When each lambda is called, the value used for val in the formula is the current value of val, therefore all your results are the same.
The solution is to "freeze" the value for val when creating each lambda function - the way that is easier to understand what is going on is to have an outer lambda function, that will take val as an input, and return your desided (inner) lambda - but with val frozen in a different scope. Note that the outer function is called and imedially discarded - its return value is the original function you had:
for i,val in enumerate(a):
print(i)
func[f'f{i}'] = (lambda val: (lambda x: x**val))(val)
shorter version
Now, due to the way Python stores default arguments to functions, it is possible to store the "current val value" as a default argument in the lambda, and avoid the need for an outer function. But that spoils the lambda signature, and the "why" that value is there is harder to understand -
for i,val in enumerate(a):
print(i)
func[f'f{i}'] = lambda x, val=val: x**val

How to use a lambda to loop without saving values

In Django I have a page where users can be added or removed from a group. I am retrieving formdata for a list of users, and then determining which ones need to be removed or added from the group. For some reason using the lambda inside map didn't affect any change, but as I understand, it should, right?
I wanted to do something like:
map(lambda x: x.group.remove(this_group).save(), users_to_remove)
map(lambda x: x.group.add(this_group).save(), users_to_add)
but it wouldn't work. I had to use loops:
for user in users_to_remove:
user.coi.remove(this_coi)
for user in users_to_add:
user.coi.add(this_coi)
I don't know what your code is supposed to do, because you did not provide an MCVE so I am hesitant to even answer this "question". However, it looks like you want to use map in order to modify an iterable in place and discard the return value of map.
You can do that, but it's a bad idea. Here's basically what you are trying to do (or what I have deduced from your code):
>>> kill = 1
>>> mylist = [[1, 2], [3, 1, 9]]
>>> map(lambda x: x.remove(kill), mylist)
[None, None]
>>> mylist
[[2], [3, 9]]
As you can see, kill was removed from every sublist, but you built a completely unnecessary, (temporarily) memory consuming list [None, None] (the return value of the lambda function for each sub-list in mylist).
You should use map when you want to apply a function to an iterable and actually care about the return value of that function, i.e. you want a new iterable of all the returnvalues. Using map to mutate an iterable in place is against its intended use (and therefore confusing to most python programmers) and inefficient.
If you need a loop, use a loop. There are no extra points for writing fewer lines.
Except when you get upvotes for a clever oneliner on SO.

Python LIST functions not returning new lists [duplicate]

This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
Closed 5 months ago.
I'm having an issue considering the built-in Python List-methods.
As I learned Python, I always thought Python mutators, as any value class mutators should do, returned the new variable it created.
Take this example:
a = range(5)
# will give [0, 1, 2, 3, 4]
b = a.remove(1)
# as I learned it, b should now be [0, 2, 3, 4]
# what actually happens:
# a = [0, 2, 3, 4]
# b = None
The main problem with this list mutator not returning a new list, is that you cannot to multiple mutations subsequently.
Say I want a list ranging from 0 to 5, without the 2 and the 3.
Mutators returning new variables should be able to do it like this:
a = range(5).remove(2).remove(3)
This sadly isn't possible, as range(5).remove(2) = None.
Now, is there a way to actually do multiple mutations on lists like I wanna do in my example? I think even PHP allows these types of subsequent mutations with Strings.
I also can't find a good reference on all the built-in Python functions. If anyone can find the actual definition (with return values) of all the list mutator methods, please let me know. All I can find is this page: http://docs.python.org/tutorial/datastructures.html
Rather than both mutating and returning objects, the Python library chooses to have just one way of using the result of a mutator. From import this:
There should be one-- and preferably only one --obvious way to do it.
Having said that, the more usual Python style for what you want to do is using list comprehensions or generator expressions:
[x for x in range(5) if x != 2 and x != 3]
You can also chain these together:
>>> [x for x in (x for x in range(5) if x != 2) if x != 3]
[0, 1, 4]
The above generator expression has the added advantage that it runs in O(n) time because Python only iterates over the range() once. For large generator expressions, and even for infinite generator expressions, this is advantageous.
Many methods of list and other mutable types intentionally return None so that there is no question in your mind as to whether you are creating a new object or mutating an existing object. The only thing that could be happening is mutation since, if a new object were created, it would have to be returned by the method, and it is not returned.
As you may have noticed, the methods of str that edit the string do return the new string, because strings are immutable and a new string is always returned.
There is of course nothing at all keeping you from writing a list subclass that has the desired behavior on .append() et al, although this seems like rather a heavy hammer to swing merely to allow you to chain method calls. Also, most Python programmers won't expect that behavior, making your code less clear.
In Python, essentially all methods that mutate the object return None.
That's so you don't accidentally think you've got a new object as a result.
You mention
I think even PHP allows these types of subsequent mutations with Strings.
While I don't remember about PHP, with string manipulations, you can chain method calls, because strings are immutable, so all string methods return a new string, since they don't (can't) change the one you call them on.
>>> "a{0}b".format(3).center(5).capitalize().join('ABC').swapcase()
'a A3B b A3B c'
Neither Python or php have built-in "mutators". You can simply write multiple lines, like
a = list(range(5))
a.remove(2)
a.remove(3)
If you want to generate a new list, copy the old one beforehand:
a = list(range(5))
b = a[:]
b.remove(2)
Note that in most cases, a singular call to remove indicates you should have used a set in the first place.
To remove multiple mutations on lists as you want to do on your example, you can do :
a = range(5)
a = [i for j, i in enumerate(a) if j not in [2, 3]]
a will be [0, 1, 4]

Categories

Resources