Phil Sheard
Phil Sheard

Reputation: 2162

"Simpler" approach to this list comprehension + product() combination

I have a dictionary with a mix of strings and lists:

sample_dict = {'numbers': [1, 2, 3], 'ref': 'some text'}

Goal is to combine and "flatten" it into an iterable of individual dictionaries that will then be used as parameters for a set of scheduled tasks via Celery:

# end goal:
[{'numbers': 1, 'ref': 'some text'},
 {'numbers': 2, 'ref': 'some text'},
 {'numbers': 3, 'ref': 'some text'}]

I tried to write it using a traditional loop to keep the code simple for later adaptation or bugfixing but I couldn't work out a way that would have access to all the necessary nested variables.

Result was to use a couple of relatively complex list comprehensions:

raw_vals = [[(i,v)] if isinstance(v,str) else ([(i,b) for b in v]) for i,v in sample_dict.items()]
end_goal = [dict(i) for i in product(*raw_vals)]

Question therefore: is there a more verbose but potentially less cryptic way to get the same result, using a standard loop or similar? I know this potentially gets into a debate about readability vs LOC, but try to ignore that if you can.

Upvotes: 1

Views: 43

Answers (2)

bruno desthuilliers
bruno desthuilliers

Reputation: 77902

Either there's something missing from your question or you overlooked the obvious:

>>> sample_dict = {'numbers': [1, 2, 3], 'ref': 'some text'}
>>> flattened = [{'numbers': num, 'ref': sample_dict['ref']} for num in      sample_dict['numbers']]
>>> print flattened
[{'ref': 'some text', 'numbers': 1}, {'ref': 'some text', 'numbers': 2}, {'ref': 'some text', 'numbers': 3}]

Upvotes: 0

Dan D.
Dan D.

Reputation: 74645

I'd suggest factoring out the conditional out of the first:

def assoc(i, v):
   if isinstance(v, list):
      return [(i, b) for b in v]
   return [(i, v)]

raw_vals = [assoc(i, v) for i, v in sample_dict.items())]
end_goal = [dict(i) for i in product(*raw_vals)]

Then the comprehensions are maps.

I also might suggest testing if the value is a list rather than a string as this would permit values to be any type other than a list and not be iterated over. This would also permit subtypes of lists to be treated as lists.

Upvotes: 2

Related Questions