test_input = {"oneone": 1, "twotwo": 2, "threethree": 3}
def testmethod(no):
print(f"Number {no}")
return True, f"Number {no}"
Without using lambda
and map
:
d = {}
for k, v in test_input.items():
ret, out = testmethod(v)
if ret:
d[k] = out
I tried below line to iterate using lambda
and map
:
>>> dict(map(lambda ref: testmethod(ref), list(test_input.values())))
{True: 'Number 3'}
Expected output using map
and lambda
:
{'oneone': 'Number 1', 'twotwo': 'Number 2', 'threethree': 'Number 3'}
CodePudding user response:
You can rewrite your loop as follows:
d = {}
for k, v in test_input.items():
tup = testmethod(v)
if tup[0]:
d[k] = tup[1]
The key is that packing and unpacking the two return values is distracting you from the fact that they are actually one return value.
Combine this insight with the walrus operator to merge the assignment and conditional lines:
if (tup := testmethod(v))[0]:
Now you have something shaped like a dictionary comprehension:
d = {k: tup[1] for k, v in test_input.items() if (tup := testmethod(v))[0]}
If you have an older version of python (pre-3.8), or want to avoid using the walrus for some other reason, you need to filter the result. Your lambda
is misplaced: lambda ref: testmethod(ref)
is just testmethod
with extra steps. The trick is to split the streams after you did the mapping. You can then filter with something like itertools.compress
:
from itertools import compress
rets, outs = zip(*map(testmethod, test_input.values()))
d = dict(compress(zip(test_input.keys(), outs), rets))
This is a fairly ugly and inefficient two-liner. You can make it a lot worse as a one liner. To do that, you turn rets, outs
into a list, reverse it, and expand it into a zip after test_input.keys()
to make an iterator that yields key, value, filter
:
d = {k: v for k, v, tf in zip(test_input. keys(), *list(zip(*map(testmethod, test_input.values())))[::-1]) if tf}
CodePudding user response:
IIUC, you want to get add a string to dict values using lambda and map. You can do:
out = dict(map(lambda x: (x[0], 'Number' str(x[1])), test_input.items()))
Output:
{'oneone': 'Number1', 'twotwo': 'Number2', 'threethree': 'Number3'}
Now, if we insist on using testmethod
, we can tweak the above lambda a bit as
out = dict(map(lambda x: (x[0], testmethod(x[1])), test_input.items()))
Output:
Number 1
Number 2
Number 3
{'oneone': 'Number 1', 'twotwo': 'Number 2', 'threethree': 'Number 3'}