Indeed, you can use a dict comprehension, but you shouldn't. If you are ready, let's go.
I will start with a little cleanup of your code.
First, I replace cpPtr.split(" ")[0]
and cpPtr.split(" ")[1]
with u
and v
, where u,v = cpPtr.split(" ")
. It's a destructuring assignement.
Then I inline the following lines:
if domainKey in domainAggregator.keys():
domainAggregator[domainKey] = int(domainAggregator[domainKey]) + int(u)
else:
domainAggregator[domainKey] = int(u)
into:
domainAggregator[domainKey] = int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)
I get now the following code:
for cpPtr in cpdomains:
u,v = cpPtr.split(" ")
for domainKey in self.domainSplitter(v):
domainAggregator[domainKey] = int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)
and I want to turn it in a dict comprehension.
Now, some little hacks.
You can't use assignements inside a list or dict comprehension. In order to put that in a list comprehension (and then a dict comprehension, see later), I need to get rid of =
s:
u, v = cpPtr.split(" ")
...
domainAggregator[domainKey] = int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)
Becomes:
for u, v in [cpPtr.split(" ")]: # this is a singleton
...
domainAggregator.update({domainKey:int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)}) # I update the dict
The code is now:
for cpPtr in cpdomains:
for u,v in [cpPtr.split(" ")]:
for domainKey in self.domainSplitter(v):
domainAggregator.update({domainKey:int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)})
Now, I can use a list comprehension to create a side-effect. You just have to insert everything inside square brackets:
[domainAggregator.update({domainKey:int(domainAggregator[domainKey])+int(u) if domainKey in domainAggregator.keys() else int(u)}) for cpPtr in cpdomains for u,v in [cpPtr.split(" ")] for domainKey in self.domainSplitter(v)]
Okay, after the evaluation of this expression, domainAggregator
has the expected value, but the list is only a list of None
s, since dict.update
returns None
.
The following codes are totally insane. Do not try to do this at home!!!
Is it possible to create a dict comprehension that returns the right value? Yes! You have to create the side effect inside the dict comprehension. Let's try this:
# does not work
{k:v for k, v in domainAggregator if len( [domainAggregator.update({domainKey:(int(domainAggregator[domainKey]) if domainKey in domainAggregator.keys() else 0) + int(u)}) for cpPtr in cpdomains for u,v in [cpPtr.split(" ")] for domainKey in self.domainSplitter(v)])>=0}
The expression:
len([domainAggregator.update({domainKey:(int(domainAggregator[domainKey]) if domainKey in domainAggregator.keys() else 0) + int(u)}) for cpPtr in cpdomains for u,v in [cpPtr.split(" ")] for domainKey in self.domainSplitter(v))>=0
is always True
and you have the desired side-effect. But this side-effect is performed each time you iterate over the items, and you get the infamous RuntimeError: dictionary changed size during iteration
.
To avoid this, you have to trigger the side effect only once.
{k:v for da in [domainAggregator for _ in range(1) if len ([domainAggregator.update({domainKey:(int(domainAggregator[domainKey]) if domainKey in domainAggregator.keys() else 0) + int(u)}) for cpPtr in cpdomains for u,v in [cpPtr.split(" ")] for domainKey in self.domainSplitter(v)])>=0] for k,v in da.items()}
The inner list tiggers the side effect and returns the dict, the outer dict comprehension iterates over the items and creates the dict.
Do not do this!!!
A MVCE: Try it online!