3
\$\begingroup\$

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.

\$\endgroup\$
8
\$\begingroup\$
  1. When you are looping over the keys a and values elements[a] of a dictionary, use the items 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.)

  2. 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:
    
  3. The code doesn't use b or d either. It is conventional to use the name _ for unused variables:

    for (_, c), _ in value:
    
  4. 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()):
    
  5. 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)
    
  6. 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.

\$\endgroup\$
6
\$\begingroup\$

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
)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.