I have a nested dictionary (category and subcategories), dict, that I am having trouble sorting.
The output of dict is:
{u'sports': {u'basketball': {'name': u'Basketball', 'slug': u'basketball'}, u'baseball': {'name': u'Baseball', 'slug': u'baseball'}}, u'dance': {u'salsa': {'name': u'Salsa', 'slug': u'salsa'}}, u'arts': {u'other-5': {'name': u'Other', 'slug': u'other-5'}, u'painting': {'name': u'Painting', 'slug': u'painting'}}, u'music': {u'cello': {'name': u'Cello', 'slug': u'cello'}, u'accordion': {'name': u'Accordion', 'slug': u'accordion'}}}
How can I sort this dictionary so that the 'other' subcategory always shows up at the end of the nested dictionary. For example the order for the "arts" category should be:
..., u'arts': {u'painting': {'name': u'Painting', 'slug': u'painting'}, u'other-5': {'name': u'Other', 'slug': u'other-5'}}...
You have some major concept misunderstanding about dictionary. Dictionary in python is like a hash table, hash table has no order. The output of the dict is really environment dependent so you couldn't depend on that. You might see one way of the output while other people see another way. You should consider using OrderedDict instead.
Python dictionaries (regular dict instances) are not sorted. If you want to sort your dict, you could:
from collections import OrderedDict
mynewdict = OrderedDict(sorted(yourdict.items()))
An OrderedDict does not provide a sorting mechanism, but only respect the order of the keys being inserted on it (we sort those keys calling sorted beforehand).
Since you need a specific criteria (lets say your keys are alphabetically ordered except for the "other" key which goes to the end), you need to declare it:
def mycustomsort(key):
return (0 if key != 'other' else 1, key)
mynewdict = OrderedDict(sorted(yourdict.items(), key=mycustomsort))
This way you are creating a tuple for the nested criteria: the first criteria is other vs. no-other, and so the 0 or 1 (since 1 is greater, other comes later), while the second criteria is the key itself. You can remove the second criteria and not return a tuple if you want, but only the 0 and 1, and the code will work without alphabetical sort.
This solution will not work if you plan to edit the dictionary later, and there is no standard class supporting that.
Related
I'm stuck on a problem from a bootcamp prep course. The problem wants me to use a function that takes in a dictionary as an argument, checks the type of the value of one of the keys, and then updates that value if the condition is met. This function works great when it's given a specific list element from a list of dictionaries.
The trouble comes when i try to nest this function into a map to apply the function to the entire list of dictionaries instead of passing in one specific element.
I've tried giving the function as the first map argument without parentheses, as was demonstrated to me in the preceding materials, and then i've tried setting the iterator as the base list of dictionaries with no index, as a [:] slice, as a [0:len{list)] slice, as a [0:2] slice, all to no avail.
# list of dictionaries to be updated, trimmed to 3 for brevity
restaurants = [{'name': 'Fork & Fig',
'price': '$$',
'is_closed': False,
'review_count': 610},
{'name': 'Salt And Board',
'price': '$$',
'is_closed': False,
'review_count': 11},
{'name': 'Stripes Biscuit',
'price': '$$',
'is_closed': True,
'review_count': 20}]
#function in question, changes the $ strings to numbers
def format_restaurant(restaurant):
if type(restaurant['price']) == str:
restaurant['price'] = len(restaurant['price'])
return restaurant
# inputting a single dictionary entry works great:
format_restaurant(restaurants[1]) # {'is_closed': False, 'name': 'Fork & Fig', 'price': 2, 'review_count': 610}
# Here comes the sticking point. The directions are:
#"Now write another function called map_format_restaurants using map, that
# uses above function and returns a list of restaurants with each of them
# formatted with price pointing to the respective number."
# My answer that I think should work, but doesn't:
def map_format_restaurants(restaurants):
map(format_restaurant, restaurants)
return restaurants
# When this function is called, the list of dictionaries comes out just as it went in:
map_format_restaurants(restaurants)
I want the code to change the '$' to 1 or the '$$' to 2 for each 'price' key value in the list of dictionaries, but none of them change. No error messages are thrown.
looking at the last dict entry in the list:
{'name': 'Stripes Biscuit',
'price': '$$',
'is_closed': True,
'review_count': 20}]
should have changed to:
{'name': 'Stripes Biscuit',
'price': 2,
'is_closed': True,
'review_count': 20}]
but instead came out just like it went in.
I'm sure this is a nice softball for someone out there, but I can't seem to hit it. Any insights would be greatly appreciated.
In Python 3, map is a lazy generator. It only runs the function when you consume it, i.e., when you ask it for elements. Until that happens, it just sits there as a map object, waiting.
One fairly standard way to consume a map is to build a list from it:
def map_format_restaurants(restaurants):
return list(map(format_restaurant, restaurants))
Remember that this creates an entirely new list, but also modifies the existing list in-place. That means that you don't need to build a new list, and can use the fastest method I know if consuming iterators only for side-effects:
from collections import deque
deque(map(format_restaurant, restaurants), maxlen=0)
The maxlen parameter ensures that the deque stays empty as it consumes the iterator.
However, given that you are modifying everything in-place, having a return value for format_restaurant is somewhat unpythonic. I would recommend using a simple for loop instead:
def format_restaurant(restaurant):
...
# no return value
for restaurant in restaurants:
format_restaurant(restaurant)
map() builds a new list. It does not modify the existing list. So modify your function to this:
def map_format_restaurants(restaurants):
return map(format_restaurant, restaurants)
Similarly, you need to assign the return value from this function:
new_restaurants = map_format_restaurants(restaurants)
I'm very new to programming and Python and trying to figure things out. I'm trying to take items out of a list and append the keys and values to a dictionary but I can't figure out how. I tried using the dictionary's Update method but I'm only getting the last item from my list, not all the items. Here is my code:
a = {}
names = [ {'name': 'Bart'}, {'name': 'Lisa'}, {'name': 'Maggie'} ]
for name in names:
a.update(name)
The result I'm getting back is:
{'name': 'Maggie'}
But I want this in my new dictionary:
{'name': 'Bart'}, {'name': 'Lisa'}, {'name': 'Maggie'}
I wanted to put the items from the list inside the dictionary in order to access the values. I need all of the names but maybe there is a much easier way to do it.
Any hints would be great. Thanks.
With same key value you cant update a dict from list of dict. You can get a dict with key a list of values.
{'name': ['Bart', 'Lisa', 'Maggie']}
a={}
for n in names:
... for k in n:
... for k,v in [(k,n[k])]:
... if k not in a:a[k]=[v]
... else: a[k].append(v)
I have a tuple with multiple dictionaries and I wish to unpack them for further use.
Let's say I have this:
tuple_to_add = {'name': 'custom1', 'value': 'first value'},{'name': 'custom2', 'value': 'second value'}
And I'd like to iterate through them
I tried something like that but it didn't give me my answer:
for value, name in tuple_to_add:
print(value)
print(name)
Dictionaries can't be unpacked in a way tuples and lists can. If you had a tuple of tuples, your way of printing would work just fine:
tuple_to_add = ('custom1', 'first value'), ('custom2', 'second value')
for name, value in tuple_to_add:
# do whatever you want
You can simply iterate over the tuple and get the actual dictionary objects which you can use to get all the necessary information:
for dc in tuple_to_add:
print(dc['value'])
print(dc['name'])
runnerList = [{1:{"name":"John","height":173,"age":16}},
{2:{"name":"Fred","height":185,"age":18}},
{3:{"name":"Luke","height":181,"age":17}}]
I've been trying to sort this list of dictionaries in ascending order according to the age of the runners, with no success :( I tried:
import operator
runnerList.sort(key=lambda x: x['age'], reverse=True)
But nothing seemed to happen. How would i do this?
Try this:
runnerList.sort(key=lambda x: x.values()[0]['age'])
print runnerList
The reason you were getting an error is that your relevant dictionaries (those containing the age key) were also contained inside another dictionary. The solution was just as simple getting the values() of that external dict and getting grabbing the first element ([0]) which gave you the only dictionary contained inside.
Also, I removed the reverse=True used in your example. It would have given you the results in descending order and you specifically asked for them to be in ascending order.
Disclaimer:
If you're using a Python version >= 3:, you'd have to convert the generator object created with values().
runnerList.sort(key=lambda x: list(x.values())[0]['age'])
runnerList is list of dictionaries of dictionaries.
if you are sure that each list entry has only one pair of key-value, then you can sort by:
runnerList.sort(key=lambda x: list(x.values())[0]['age'], reverse=True)
if each list entry has more then one key-value pair, then you need to specify better the logic of your sort. what would you do on list like this?:
runnerList = [{1:{"name":"John","height":173,"age":16}},
{ 2:{"name":"Fred","height":185,"age":18},
4:{"name":"Fred","height":185,"age":13}
},
{3:{"name":"Luke","height":181,"age":17}}]
You basically have the runnerList in form of list as it is enclosed in []. First change it to dictionary like
runnerList = {1:{"name":"John","height":173,"age":16},
2:{"name":"Fred","height":185,"age":18},
3:{"name":"Luke","height":181,"age":17} }
and then you can import operator and can use the below function to sort the items and print it
sorted_runnerList = sorted(runnerList.items(),key=lambda x: x[1]['age'],)
While this would directly sort the age in the dictionary within the dictionary
So basically your function becomes
import operator
runnerList = {1:{"name":"John","height":173,"age":16},
2:{"name":"Fred","height":185,"age":18},
3:{"name":"Luke","height":181,"age":17} }
sorted_runnerList = sorted(runnerList.items(),key=lambda x: x[1]['age'],)
print sorted_runnerList
But do remember as we are using the .items() it would return immutable tuples
Output
[(1, {'age': 16, 'name': 'John', 'height': 173}), (3, {'age': 17, 'name': 'Luke', 'height': 181}), (2, {'age': 18, 'name
': 'Fred', 'height': 185})]
I'm trying to sort this dict based on the key "order". Kindly, find below sample dict :-
{'about-us': [{'name': 'CONSTITUTION', 'order': u'2', 'uri': 'constitution'},
{'name': 'EXECUTIVE COMMITTEE',
'order': u'3',
'uri': 'executive-committee'},
{'name': 'FINANCIAL INFO',
'order': u'4',
'uri': 'financial-info'},
{'name': 'SPONSORS AND AFFILIATIONS',
'order': u'5',
'uri': 'sponsors-and-affiliations'},
{'name': 'ABOUT', 'order': u'1', 'uri': 'about'}]}
Tried using this code, but I got an error
sorted(sub_links, key=lambda x: sub_links[x]['order'])
TypeError: list indices must be integers, not str
Any hint?
You can't sort the dictionary itself. Dictionary in python does not have an order.
Trying to sort dictionary will pass keys of the dictionary to the key function. sub_links[x] => sub_links['about-us']; sub_links[x]['order'] fails because sub_links[x] returns a list.
You can sort the list inside the dictionary: d['about-us']
Also the usage of the sorted function should be changed: sorted passes each item to the key function, not the index of the item.
>>> sorted(d['about-us'], key=lambda x: int(x['order']))
[{'uri': 'about', 'name': 'ABOUT', 'order': u'1'},
{'uri': 'constitution', 'name': 'CONSTITUTION', 'order': u'2'},
{'uri': 'executive-committee', 'name': 'EXECUTIVE COMMITTEE', 'order': u'3'},
{'uri': 'financial-info', 'name': 'FINANCIAL INFO', 'order': u'4'},
{'uri': 'sponsors-and-affiliations', 'name': 'SPONSORS AND AFFILIATIONS', 'order': u'5'}]
If you need to sort all the dictionary values in place, loop over the values.
for value in d.values(): # use `itervalues` In Python 2.x
value.sort(key=lambda x: int(x['order']))
falsetru showed what you probably meant to do, but here's an explanation of the error you are seeing:
The key lambda function receives the dictionary's keys as its argument x when called--in this case, the call looks something like this when performed on the one and only key in the dictionary:
# this is JUST for demonstrating the execution of the code--this is not actual Python code
lambda("about-us"):
return sub_links["about-us"]["order"]
When this executes, sub_links["about-us"] returns the value of that key, which is a list. When the next part of the statement executes (<the list that got returned>["order"]), the TypeError gets thrown because lists require integer indices.
There's a bigger problem here--it seems you called sorted on the whole dictionary, which only contains 1 value. It doesn't make sense to sort something with only 1 entry, and it should not be used to sort what you seem to want to sort, which is the inner list of dictionaries.
If you want to sort the inner list of dictionaries (the corresponding dict value for the "about-us" key), you'll need something like this (as falsetru also suggested):
sorted(sub_links["about-us"], key=lambda d: int(d["order"]))