lambda in python can iterate dict? - python

I have an interview recently. The interviewer asked me the ways to iterate dict in python. I said all the ways use for statement. But he told me that how about lambda?
I feel confused very much and I consider lambda as an anonymity function, but how it iterates a dict? some code like this:
new_dict = sorted(old_dict.items(), lambda x: x[1]) # sorted by value in dict
But in this code, the lambda is used as a function to provide the compared key. What do you think this question?

You don't iterate with lambda. There are following ways to iterate an iterable object in Python:
for statement (your answer)
Comprehension, including list [x for x in y], dictionary {key: value for key, value in x} and set {x for x in y}
Generator expression: (x for x in y)
Pass to function that will iterate it (map, all, itertools module)
Manually call next function until StopIteration happens.
Note: 3 will not iterate it unless you iterate over that generator later. In case of 4 it depends on function.
For iterating specific collections like dict or list there can be more techniques like while col: remove element or with index slicing tricks.
Now lambda comes into the picture. You can use lambdas in some of those functions, for example: map(lambda x: x*2, [1, 2, 3]). But lambda here has nothing to do with iteration process itself, you can pass a regular function map(func, [1, 2, 3]).

You can iterate dict using lambda like this:
d = {'a': 1, 'b': 2}
values = map(lambda key: d[key], d.keys())

Using a plain lambda to iterate anything in Python sounds very wrong. Certainly the most Pythonic method to iterate sequences and collections is to use list comprehensions and generator expressions like #Andrey presented.
If the interviewer was leaning on the more theoretical/Computer Sciencey answers, it is worth noting that using lambdas to iterate is quite possible, although I must stress that this is not Pythonic nor useful at any context other than academic exercises:
# the legendary Y combinator makes it possible
# to let nameless functions recurse using an indirection
Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
# our iterator lambda
it = lambda f: lambda Lst: (Lst[0], f(Lst[1:])) if Lst else None
# see it in action:
Y(it)([1,2,3])
=> (1, (2, (3, None)))

lambda itself doesn't iterate anything. As you thought, it just defines an anonymous function - aside from the syntactic rule about only being able to have an expression, a lambda does nothing more than a similar function made using def. The code inside the lambda might iterate something, but only in the same ways as any other function might use (provided they are expressions, and so valid inside a lambda).
In the example you mention using sorted, the key function is called on each element of the list being sorted - but it is sorted itself that does this, and which does the iteration. When you provide a key function, sorted does something broadly similar to this:
def sorted(seq, key):
decorated = [(key(elem), i) for i, elem in enumerate(seq)]
# Sort using the normal tuple lexicographic comparisons
decorated.sort()
return [seq[i] for _,i in decorated]
As you can see, sorted does the iteration here, not the lambda. Indeed, there is no reason why the key has to be a lambda - any function (or any callable) will do as far as sorted is concerned.
At the lowest level, there is only really one way to iterate a dict (or, indeed, any other iterable) in Python, which is to use the iterator protocol. This is what the for loop does behind the scenes, and you could also use a while statement like this:
it = iter(my_iterable)
while True:
try:
val = next(it)
except StopIteration:
# Run else clause of for loop
break
else:
# Run for loop body
The comments in this aren't strictly part of the iterator protocol, they are instead part of the for loop (but having at least a loop body in there is mostly the point of iterating in the first place).
Other functions and syntax that consume iterables (such as list, set and dict comprehensions, generator expressions or builtins like sum, sorted or max) all use this protocol, by either:
Using a Python for loop,
Doing something like the above while loop (especially for modules written in C),
Delegating to another function or piece of syntax that uses one of these
A class can be made so that its instances become iterable in either of two ways:
Provide the iterator protocol directly. You need a method called __iter__ (called by iter), which returns an iterator. That iterator has a method called __next__ (just next in Python 2) which is called by next and returns the value at the iterator's current location and advances it (or raises StopIteration if it is already at the end); or
Implement part of the sequence protocol (which means behaving like a list or tuple). For forward iteration, it is sufficient to define __getitem__ in such a way that doing my_sequence[0], my_sequence[1], up until my_sequence[n-1] (where n is the number of items in the sequence), and higher indexes raise an error. You usually want to define __len__ as well, which is used when you do len(my_sequence).

Dictionary iteration using lambda
dct = {1: '1', 2 : '2'}
Iterating over Dictionary using lambda:
map(lambda x : str(x[0]) + x[1], dct.iteritems())
here x[0] is the key
and x[1] is the value
Result :
['11', '22']
Filtering on Dictionary using lambda:
filter(lambda x : x[0] > 1, dct.iteritems())
Result :
[(2, '2')]

The best way to iterate dict in python is:
dic ={}
iter_dic = dic.iteritems().next
iter_dic()
...
iter_dic()
But you can build it with lambda func:
iter_dic = lambda dic: dic.keys()[0],dic.pop(dic.keys()[0])
iter_dic(dic)
...
iter_dic(dic)

Could we say
count = {8: 'u', 4: 't', 9: 'z', 10: 'j', 5: 'k', 3: 's'}
count_updated = dict(filter(lambda val: val[0] % 3 == 0,
count.items()))
is iterating Dictionary with Lambda function?
It will produce:
   {8: 'u', 4: 't', 9: 'z', 10: 'j', 5: 'k', 3: 's'}
   {9: 'z', 3: 's'}
from Python dictionary filter + Examples.

Related

How to pass arguments to a function in "map" function call?

I know a map function gets a function as its first argument and the next arguments are iterators on which the passed function needs to be applied. My question here is say if I have a 2d list like so
l=[[1,2,3],[4,5,6],[7,8,9]]
how can I sort the individual lists in reverse order so my output is
l=[[3,2,1],[6,5,4],[9,8,7]]
I know a potential solution is using a lambda function such as
list(map(lambda x:x[::-1],l))
I want something like this
list(map(sorted, l,'reversed=True'))
where 'reversed=True' is an argument that sorted takes
eg:
>>> newList=[1,2,3]
>>> sorted(newList,reversed='True')
>>> [3,2,1]
I have seen how to pass arguments to a the pow function using the itertools.repeat module
map(pow,list,itertools.repeat(x))
x=power to which the list must be raised
I want to know if there is any way the arguments can be passed in a map function. In my case the 'reverse=True' for the sorted function.
You can use functools.partial for this:
import functools
new_list = list(map(functools.partial(sorted, reverse=True), l))
You can use a lambda to wrap the funtion:
map(lambda x: sorted(x, reversed=True), l)
or:
map(lambda i, j: pow(i, j), list,itertools.repeat(x))
There are many ways to do it.
You could use functools.partial. It creates a partial, for the lack of a better word, of the function you pass to it. It sort of creates a new function with some parameters already passed into it.
For your example, it would be:
from functools import partial
rev_sort = partial(sorted, reverse=True)
map(rev_sort, l)
The other way is using a simple lambda:
map(lambda arr: sorted(arr, reverse=True), l)
The other other way (my personal choice), is using generators:
(sorted(arr, reverse=True) for arr in l)
For this specific case, you can also use a list comprehension -
l=[[1,2,3],[4,5,6],[7,8,9]]
l = [list(reversed(sublist)) for sublist in l]
//[[3,2,1],[6,5,4],[9,8,7]]

Lambda function syntax in python

I came across the sorted() example below and cannot figure out why lambda student: student[2] can represent a function specifying the integers in the tuple.
Can anyone lay out the mechanics or a clearer example of how python knows the lambda function student should pull data from student_tuples?
student_tuples = [
('john', 'A', 15),
('jane', 'B', 12),
('dave', 'B', 10)]
sorted(student_tuples, key=lambda student: student[2]) # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
lambda student: student[2] is equivalent to the following function, aside from not having a name:
def <anonymous function>(student):
return student[2]
The reason why it winds up pulling from student_tuples is because the sorted() function passes each individual element from its first argument (the sequence to sort) to its key argument (a function that takes an element and returns the corresponding sort key). As such, sorted() passes each element of student_tuples to the lambda function in turn, during which the value of the element is temporarily assigned to the student variable.
lambda student: student[2]
clearer:
lambda x: x[2]
A lambda expression returns a function. The arguments for this function are before the ':' and separated by commas.
lambda x,y: x + y
The function does not have a name. But you can imagine as if lambda creates an abstract function. The lambda expression returns a function.
(Lambda is kind of essence of what a function is).
You can give lambda expressions also a name:
f = lambda x: x[2]
And now you can use the name to call the function.
f(["a", "b", "c"]) ## returns "c" because the list element "c" has index 2
list(map(f, student_tuples))
## [15, 12, 10]
or with the lambda expression:
list(map(lambda x: x[2], student_tuples))
## [15, 12, 10]
is actually what happens inside of sort:
the lambda-function is applied to each element of the list (map).
The outer list() around map() is necessary to execute map, because map is lazily evaluated (a promise to execute it but not yet executed).
Lazy evaluation is actually a nesting of lambdas ... well, lambdas are the core of functional programming. Programming languages like Lisp make you clear what lambda actually is. (You can also google for lambda calculus).
In R, a functional language, in such case the order of the iterable object indexes is determined and then applied on the object - for the ordering/sorting - to achieve the final sorted version (function sort)
I guess, sth similar is going on inside Python's sorted function.

Converting list to dict python

Given a list:
source = [{'A':123},{'B':234},{'C':345}]
I need a dict from this list in the format:
newDict = {'A':123,'B':234,'C':345}
What is the syntactically cleanest way to accomplish this?
Use a dict-comprehension:
>>> l = [{'A':123},{'B':234},{'C':345}]
>>> d = {k: v for dct in l for k, v in dct.items()}
>>> d
{'A': 123, 'B': 234, 'C': 345}
However it's probably opinion-based if that's the "syntactically cleanest way" but I like it.
Here's an additional approach, provided here to give you a flavor for how Python implements the functional programming technique called reduction, via the reduce() function. In Python 3, reduce() is in the functools package. In Python 2, reduce() is a built-in function. I use Python 3 in the example below:
from functools import reduce # don't import if you are using Python 2
def updater(dict_orig, dict_add):
dict_orig.update(dict_add)
return dict_orig
new_dict = reduce(updater, l, dict())
The first argument to reduce() is the function to operate on the iterable, the second is the iterable itself (your list l), and the third is the optional initializer object to put at the beginning of the list to reduce.
Each step of the reduction requires an object to be operated on: namely, the result of the previous step. But dict.update() does not return anything, so we need the updater() function above, which performs the update and then returns the dict being updated, thus providing the required object for the next step. Were it not for dict.update() not having a return value, this would all be a one-liner.
Because dict.update() operates directly on the original dict, we need that optional empty dict() initializer object to start out the reduction - without it, the first dict in your original l list would be modified.
For all these reasons, I like #MSeifert's dict-comprehension approach much better, but I posted this anyway just to illustrate Python reduction for you.
If you use it often, you might want to define a merge function, which you can then pass to reduce :
from functools import reduce # Needed for Python3
source = [{'A':123},{'B':234},{'C':345}]
def merge(a,b):
d = a.copy()
d.update(b)
return d
print(reduce(merge, source))
#=> {'A': 123, 'C': 345, 'B': 234}

modifying argument value within function

I am trying to figure out a way to modify the order of a list of tuples within a function without returning the list.
For example:
L = [(2,4),(8,5),(1,3),(9,4)]
def sort_ratios(L):
L = sorted(L, key=lambda x: float(x[0])/float(x[1]))
return L
Thus, calling sort_ratios() outputs:
>>>sort_ratios(L)
[(1,3),(2,4),(8,5),(9,4)]
But L would still be [(2,4),(8,5),(1,3),(9,4)]
Instead, I would like to simply modify the value of L without returning anything so that sort_ratios() operates as follows:
>>>sort_ratios(L)
>>>L
[(1,3),(2,4),(8,5),(9,4)]
It seems trivial, but I just can't seem to get the function to operate this way.
Try L.sort(key=lambda x: float(x[0])/float(x[1])) for an in-place sort.

Is there a 'foreach' function in Python 3?

When I meet the situation I can do it in javascript, I always think if there's an foreach function it would be convenience. By foreach I mean the function which is described below:
def foreach(fn,iterable):
for x in iterable:
fn(x)
they just do it on every element and didn't yield or return something,i think it should be a built-in function and should be more faster than writing it with pure Python, but I didn't found it on the list,or it just called another name?or I just miss some points here?
Maybe I got wrong, cause calling an function in Python cost high, definitely not a good practice for the example. Rather than an out loop, the function should do the loop in side its body looks like this below which already mentioned in many python's code suggestions:
def fn(*args):
for x in args:
dosomething
but I thought foreach is still welcome base on the two facts:
In normal cases, people just don't care about the performance
Sometime the API didn't accept iterable object and you can't rewrite its source.
Every occurence of "foreach" I've seen (PHP, C#, ...) does basically the same as pythons "for" statement.
These are more or less equivalent:
// PHP:
foreach ($array as $val) {
print($val);
}
// C#
foreach (String val in array) {
console.writeline(val);
}
// Python
for val in array:
print(val)
So, yes, there is a "foreach" in python. It's called "for".
What you're describing is an "array map" function. This could be done with list comprehensions in python:
names = ['tom', 'john', 'simon']
namesCapitalized = [capitalize(n) for n in names]
Python doesn't have a foreach statement per se. It has for loops built into the language.
for element in iterable:
operate(element)
If you really wanted to, you could define your own foreach function:
def foreach(function, iterable):
for element in iterable:
function(element)
As a side note the for element in iterable syntax comes from the ABC programming language, one of Python's influences.
Other examples:
Python Foreach Loop:
array = ['a', 'b']
for value in array:
print(value)
# a
# b
Python For Loop:
array = ['a', 'b']
for index in range(len(array)):
print("index: %s | value: %s" % (index, array[index]))
# index: 0 | value: a
# index: 1 | value: b
map can be used for the situation mentioned in the question.
E.g.
map(len, ['abcd','abc', 'a']) # 4 3 1
For functions that take multiple arguments, more arguments can be given to map:
map(pow, [2, 3], [4,2]) # 16 9
It returns a list in python 2.x and an iterator in python 3
In case your function takes multiple arguments and the arguments are already in the form of tuples (or any iterable since python 2.6) you can use itertools.starmap. (which has a very similar syntax to what you were looking for). It returns an iterator.
E.g.
for num in starmap(pow, [(2,3), (3,2)]):
print(num)
gives us 8 and 9
The correct answer is "python collections do not have a foreach". In native python we need to resort to the external for _element_ in _collection_ syntax which is not what the OP is after.
Python is in general quite weak for functionals programming. There are a few libraries to mitigate a bit. I helped author one of these infixpy
pip install infixpy https://pypi.org/project/infixpy/
from infixpy import Seq
(Seq([1,2,3]).foreach(lambda x: print(x)))
1
2
3
Also see: Left to right application of operations on a list in Python 3
Here is the example of the "foreach" construction with simultaneous access to the element indexes in Python:
for idx, val in enumerate([3, 4, 5]):
print (idx, val)
Yes, although it uses the same syntax as a for loop.
for x in ['a', 'b']: print(x)
This does the foreach in python 3
test = [0,1,2,3,4,5,6,7,8,"test"]
for fetch in test:
print(fetch)
Look at this article. The iterator object nditer from numpy package, introduced in NumPy 1.6, provides many flexible ways to visit all the elements of one or more arrays in a systematic fashion.
Example:
import random
import numpy as np
ptrs = np.int32([[0, 0], [400, 0], [0, 400], [400, 400]])
for ptr in np.nditer(ptrs, op_flags=['readwrite']):
# apply random shift on 1 for each element of the matrix
ptr += random.choice([-1, 1])
print(ptrs)
d:\>python nditer.py
[[ -1 1]
[399 -1]
[ 1 399]
[399 401]]
If I understood you right, you mean that if you have a function 'func', you want to check for each item in list if func(item) returns true; if you get true for all, then do something.
You can use 'all'.
For example: I want to get all prime numbers in range 0-10 in a list:
from math import sqrt
primes = [x for x in range(10) if x > 2 and all(x % i !=0 for i in range(2, int(sqrt(x)) + 1))]
If you really want you can do this:
[fn(x) for x in iterable]
But the point of the list comprehension is to create a list - using it for the side effect alone is poor style. The for loop is also less typing
for x in iterable: fn(x)
I know this is an old thread but I had a similar question when trying to do a codewars exercise.
I came up with a solution which nests loops, I believe this solution applies to the question, it replicates a working "for each (x) doThing" statement in most scenarios:
for elements in array:
while elements in array:
array.func()
If you're just looking for a more concise syntax you can put the for loop on one line:
array = ['a', 'b']
for value in array: print(value)
Just separate additional statements with a semicolon.
array = ['a', 'b']
for value in array: print(value); print('hello')
This may not conform to your local style guide, but it could make sense to do it like this when you're playing around in the console.
In short, the functional programming way to do this is:
def do_and_return_fn(og_fn: Callable[[T], None]):
def do_and_return(item: T) -> T:
og_fn(item)
return item
return do_and_return
# where og_fn is the fn referred to by the question.
# i.e. a function that does something on each element, but returns nothing.
iterable = map(do_and_return_fn(og_fn), iterable)
All of the answers that say "for" loops are the same as "foreach" functions are neglecting the point that other similar functions that operate on iters in python such as map, filter, and others in itertools are lazily evaluated.
Suppose, I have an iterable of dictionaries coming from my database and I want to pop an item off of each dictionary element when the iterator is iterated over. I can't use map because pop returns the item popped, not the original dictionary.
The approach I gave above would allow me to achieve this if I pass lambda x: x.pop() as my og_fn,
What would be nice is if python had a built-in lazy function with an interface like I constructed:
foreach(do_fn: Callable[[T], None], iterable: Iterable)
Implemented with the function given before, it would look like:
def foreach(do_fn: Callable[[T], None], iterable: Iterable[T]) -> Iterable[T]:
return map(do_and_return_fn(do_fn), iterable)
# being called with my db code.
# Lazily removes the INSERTED_ON_SEC_FIELD on every element:
doc_iter = foreach(lambda x: x.pop(INSERTED_ON_SEC_FIELD, None), doc_iter)
No there is no from functools import foreach support in python. However, you can just implement in the same number of lines as the import takes, anyway:
foreach = lambda f, iterable: (*map(f, iterable),)
Bonus:
variadic support: foreach = lambda f, iterable, *args: (*map(f, iterable, *args),) and you can be more efficient by avoiding constructing the tuple of Nones

Categories