(See Update at the end, for the response to the statement in a comment by the user)
In the itertools
module you have the chain
function, designed to link several iterables in lazy form (that is, without having to generate and store in memory the lists of each iterable to be able to add them).
Example:
d1 = { "a": 1, "b": 2}
d2 = { "b": 3, "c": 4}
d3 = { "a": 2, "b": 5, "f": 6}
from itertools import chain
for k,v in chain(d1.items(), d2.items(), d3.items()):
print(k,v)
Print
a 1
b 2
b 3
c 4
a 2
b 5
f 6
Version with functional programming
I know what you're thinking. That of d1.items(), d2.items(), d3.items()
is a repetition that "smells a bit bad". Maybe it could be avoided.
For example, what if all the dictionaries were in a list, for example datos = [d1, d2, d3]
? How to invoke .items()
in each element to apply chain()
to the result?
A simple way is to use a generating expression to apply .item()
, and the unpacked operator *
to convert the resulting iterable into a series of parameters for chain()
. So:
datos = [d1, d2, d3]
for k,v in chain(*(d.items() for d in datos)):
print(k,v)
This is for me the most readable and pythonica form. But you know that Python also supports the functional programming paradigm, although for my taste the syntax becomes more obfuscated. Although mathematicians tend to like this more:
from itertools import chain
from operator import methodcaller
from functools import partial
getitems = partial(methodcaller("items"))
for k, v in chain(*map(getitems, datos)):
print(k,v)
If someone is interested in explaining how this works, you can leave a comment.
Update
Sorry. So focused was the question of how to "concatenate" the dictionaries to iterate on them, that I did not notice that during the loop those dictionaries were being modified.
Input a note about modifying iterables while iterating over them. It is forbidden (not strictly, but the result is unpredictable) adding or removing elements to the iterable while iterating through it. However, this is not the case in the user's question, what he does is modify the value stored in the keys.
That's for sure, but the mechanisms based on chain()
are not applicable, because with these mechanisms we have only the keys and the values, but not the references to the original dictionaries to be able to change elements.
Fortunately, the solution is extremely simple. In fact, this same solution would be usable even if the elements are not changed and therefore it is an alternative to chain()
, and to that proposed in other answers. Just make a nested loop! One iterates through the dictionaries and the other through the elements of each dictionary.
For example, the following code changes the value stored in each key of each dictionary by twice the value it had:
for d in (d1, d2, d3):
for k,v in d.items():
d[k] = 2*v
In your case:
for d in (redirections, redirections2, redirections3):
for k, v in d.items():
new_id = list(filter(lambda a: v == a.dialog.peer.channel_id, dialogs))[0].id
d[k] = new_id
Side note The list(filter(...))
can be changed to a list comprehension that in the opinion of many (including Guido) is more readable:
new_id = [a for a in dialogs if a.dialog.peer.channel_id==v][0].id