I have a dictionary structured as {a_1: [((b_11,c_11),d_11), ((b_12, c_12), d_12), ...], a_2: [...], ...}
.
I want to extract the maximum abs(c) among all the possible c values. Currently I'm doing this throught two for loops. One for each a, and other for each of set {b,c,d}.
elements = {
0: [((0, -4), 1)],
1: [((1, -5), 1), ((0, -4), 1)],
2: [((2, -3), 1)],
3: [((3, -2), 1), ((0, -5), 1)],
}
max_c = 0
for a in list(elements):
for (b, c), d in elements[a]:
max_c = max(max_c, abs(c))
Is there any way to do this without the for loops? and if it is, is it pythonic? or I should keep this way because it's more understandable?
Thanks in advance.
2 Answers 2
When you are looping over the keys
a
and valueselements[a]
of a dictionary, use theitems
method to loop over both at the same time:for a, value in elements.items(): for (b, c), d in value:
(If I knew what these values represented, I would pick a better name than
value
.)The code here doesn't use the keys, it only uses the values. So use the
values
method instead:for value in elements.values(): for (b, c), d in value:
The code doesn't use
b
ord
either. It is conventional to use the name_
for unused variables:for (_, c), _ in value:
A double iteration over some lists and then over the elements of those lists can be combined into a single iteration using
itertools.chain.from_iterable
:from itertools import chain for (_, c), _ in chain.from_iterable(elements.values()):
The repeated calls to
max
can become a single call taking a generator expression:values = chain.from_iterable(elements.values()) max_abs_c = max(abs(c) for (_, c), _ in values)
It's common to worry whether code is "Pythonic" but it is better to think in terms of general principles (clarity, simplicity, maintainability, testability, usability, efficiency, etc.) that apply to code in any language.
If you were to extract all abs(c)
into a list, you could use max
over that list.
Fortunately, this is easy using your loops and a list-comprehension:
Cs = [
abs(value)
for collection in elements.values()
for (_, value), _ in collection
]
max_c = max(Cs)
Note the use of elements.values()
instead of extracting the values manually (elements[a]
) and the use of _
as a throwaway variable.
Now max
works on any iterable, meaning we don't even have to build a temporary list and can feed it a generator-expression:
max_c = max(
abs(value)
for collection in elements.values()
for (_, value), _ in collection
)