Reputation: 73
Quite a basic question but I am still not very good at making my code more compact. Is there a less verbose way of navigating multiple nested dicts in a list than what I have currently got?
myset = set(())
for element in nested_list:
for value in element.values():
for item in value.items():
myset.add(item)
As a follow up, does it really matter if it is overly verbose?
Example data:
nested_list = [{
"2020/48": {
"Paradise": "Meduza",
"Positions": "Ariana Grande",
"Therefore I Am": "Billie Eilish"
}
}, {
"2020/47": {
"Therefore I Am": "Billie Eilish",
"Positions": "Ariana Grande",
"Paradise": "Meduza",
"You Broke Me First": "Tate Mcrae"
}
}]
Just for reference, it is top 100 song chart data with each element in the list being a different week.
Upvotes: 0
Views: 71
Reputation: 51093
Your code isn't overly verbose; the nested loops are necessary to process a nested data structure. I think there are only two things that can possibly be cut out: the explicit call to myset.add
can be done implicitly with a set comprehension or some other way of collecting values in a set, and the innermost loop can be replaced with some bulk operation which deals with the whole of .items()
at once rather than each element from it individually.
Here are a few options. A set comprehension at least avoids several layers of indentation:
result = {
item
for element in nested_list
for value in element.values()
for item in value.items()
}
You can use set.union
with the argument unpacking operator, but this looks a bit ugly. Unfortunately set.union
doesn't accept value.items()
directly even though it is a set-like object, but set().union
works because only the "self" parameter needs to be a real set.
result = set().union(*(
value.items()
for element in nested_list
for value in element.values()
))
Or you can use itertools:
from itertools import chain
result = set(chain.from_iterable(
value.items()
for element in nested_list
for value in element.values()
))
And here's a bonus version with no loops, because every question like this deserves an unreadable one-line answer that should not actually be used:
set().union(*map(dict.items, chain.from_iterable(map(dict.values, nested_list))))
Personally I prefer the set comprehension, since it's syntactically cleaner and it's more obvious what it does, even though it has one more loop.
Upvotes: 2
Reputation: 52008
One possibility is to first flatten the data structure a bit with a dictionary comprehension:
week = {k:v for d in nested_list for k,v in d.items()}
Then e.g. week["2020/48"]
will give you the inner dictionary for that week.
Given that, a set comprehension can now extract the data you want:
myset = {item for d in week.values() for item in d.items()}
Upvotes: 0
Reputation: 522382
One obvious improvement would be the last inner loop, which you can condense to this:
for element in nested_list:
for value in element.values():
myset.update(value.items())
Instead of adding each element one by one, update the set with the dict items directly. Other than this, there are of course many ways to bend over backwards and make it shorter somehow, but that wouldn't necessarily improve the code.
Upvotes: 1