I'm looking for alternatives to using comprehensions for nested data structures or ways to get comfortable with nested list comprehensions if possible.
Without comprehensions generating a list of items using a nested loop works like this:
combos = []
for a in iterable:
for b in valid_posibilities(a):
combos.append((a,b))
turning this into a comprehension retains the order of the loops which makes using multiple lines nice:
combos = [
(a,b)
for a in iterable
for b in valid_posibilities(a)
]
However this creates a single list. If I want some code to produce a nested data structure then I would use something like this:
# same as above but instead of list of (a,b) tuples,
# I want a dictionary of {a:[b]} structure
combos_map = {}
for a in iterable:
options = []
for b in valid_posibilities(a):
options.append(b)
combos_map[a] = options
(the following snippet has the equivalent code using plain lists for those who haven't seen dictionary comprehension before and the first time seeing it being nested in a weird way is hard to follow)
# for people unfamilar with dictionary comprehension
# this is the equivelent nesting structure
combos = []
for a in iterable:
options = []
for b in valid_posibilities(a):
options.append(b)
combos.append(options)
######## or equivelently
combos = [
[b
for b in valid_posibilities(a)
]
for a in iterable
]
Now converting it to a comprehension we get this:
combos_map = {
a:[b
for b in valid_posibilities(a)
]
for a in iterable
}
What the heck? The order of the loops switched! This is because the inner loop has to be put inside the inner list. If it was just always reversed when you want a nested data structure I'd be fine but conditions or non-nesting loops make it worse:
# for a list of files produce a mapping of {filename:(set of all words)}
# only in text files.
file_to_words_map = {}
for filename in list_of_files:
if filename.endswith(".txt"):
word_set = set()
for line in open(filename):
for word in line.split():
word_set.add(word)
file_to_words_map[filename] = word_set
### or using comprehension we get this lovely mess:
file_to_words_map = {
filename: { word
for line in open(filename)
for word in line.split()
}
for filename in list_of_files
if filename.endswith(".txt")
}
I teach python to beginners and on the occasion that someone wants to generate a nested data structure with comprehensions and I tell them 'it isn't worth it' I'd like to be able to send them here as a nicer explanation for why.
So for the people I will send here I'm looking for is one of the following:
Is there another way to refactor these kinds of loops that make the code easier to follow instead of just directly sticking them in comprehensions?
is there a way to interpret and construct these nested loops in an intuitive way? At some point someone who is not familiar with python comprehensions will stumble across some code like the ones shown here and hopefully will end up here looking for some insight.