roulette01
roulette01

Reputation: 2472

Dict comprehension over multiple dicts with missing keys

I have a piece of legacy python2 code that looks like the following

    # dict1 and dict2 are inputs. dict2 is where the value is a 4-tuple
    return {
        key: [
            NamedTuple1(val1, val2, val3, val4),
            NamedTuple2(
                dict2.get(key, (None, None, None, None))[0],
                dict2.get(key, (None, None, None, None))[1],
                dict2.get(key, (None, None, None, None))[2],
                dict2.get(key, (None, None, None, None))[3],
            ),
        ]
        for key, (val1, val2, val3, val4) in dict1.items()
    }

I don't like this code because it does dict2.get(key, (None, None, None, None)) 4x every iteration, and I feel like there should be a simpler way to write this. Is there a way to put the dict2 in the for loop and for missing key, just return a (None, None, None, None) and then unwrap this within NamedTuple2?

Upvotes: 0

Views: 33

Answers (2)

jsbueno
jsbueno

Reputation: 110591

It is possible to simply do "star-unpacking" in the call to NamedTuple2:

    # dict1 and dict2 are inputs. dict2 is where the value is a 4-tuple
    return {
        key: [
            NamedTuple1(val1, val2, val3, val4),
            NamedTuple2(
                *dict2.get(key, (None, None, None, None))
            ),
        ]
        for key, (val1, val2, val3, val4) in dict1.items()
    }

Upvotes: 0

Tamas Hegedus
Tamas Hegedus

Reputation: 29936

I think you should be able to use argument unpacking in this particular example. The only assumption is every value in dict2 needs to be 4 items long.

# dict1 and dict2 are inputs. dict2 is where the value is a 4-tuple
return {
    key: [
        NamedTuple1(val1, val2, val3, val4),
        NamedTuple2(*dict2.get(key, (None, None, None, None))),
    ]
    for key, (val1, val2, val3, val4) in dict1.items()
}

If that doesn't work for you, then I suggest to extract part of the comprehesion into a function:

# dict1 and dict2 are inputs. dict2 is where the value is a 4-tuple
return {
    key: extract_value(dict2, key, val1, val2, val3, val4)
    for key, (val1, val2, val3, val4) in dict1.items()
}
....
def extract_key(dict2, key, val1, val2, val3, val4):
    dict2value = dict2.get(key, (None, None, None, None))
    return [
        NamedTuple1(val1, val2, val3, val4),
        NamedTuple2(
            dict2value[0],
            dict2value[1],
            dict2value[2],
            dict2value[3],
        ),
    ]

Upvotes: 1

Related Questions