PROBLEM
I have a dictionary and it is nested i want to sort it using vlaues. There are many solution out there for the same question but I couldnt find one solution that satisfies my sorting condition
CONDITION
I want to sort thee dict in descending order of the given likes in the dict
Dict
dict = {actor_name: {movie_name: likes}
eg:- {'gal gadot': {'red notice': 1000}, 'tom holland': {'spiderman-nwh': 3000}}
output should be:- {'tom holland': {'spiderman-nwh': 3000}, 'gal gadot': {'red notice': 1000}}
I suggest improving your data structure first.
As an example you could use a list of dictionaries list[dict].
This would help you later, if you expand your structure.
Try this structure:
data = [
{
"actor": "gal gadot",
"movies": {
"name": "red notice",
"likes": 1000,
},
},
{
"actor": "tom holland",
"movies": {
"name": "spiderman-nwh",
"likes": 3000,
},
},
]
Using that structure, you can sort your data like this:
# Least likes first
least_likes_sorted = = sorted(data, key=lambda x: x["movies"]["likes"])
# Most likes first
most_likes_sorted = sorted(data, key=lambda x: x["movies"]["likes"], reverse=True)
You could build a list of tuples where each element is (likes, movie, actor).
Then sort the list in reverse.
Then reconstruct your dictionary.
Like this:
data = {'gal gadot': {'red notice': 1000}, 'tom holland': {'spiderman-nwh': 3000}}
lot = []
for k, v in data.items():
k_, v_ = next(iter(v.items()))
lot.append((v_, k_, k))
newdata = {a : {b: c} for c, b, a in sorted(lot, reverse=True)}
print(newdata)
Output:
{'tom holland': {'spiderman-nwh': 3000}, 'gal gadot': {'red notice': 1000}}
Related
I have a list of dictionaries where I want to get a new list of dictionaries with unique two keys: 1. City, 2. Country.
list = [
{ City: "Gujranwala", Country: "Pakistan", other_columns },
{ City: "Gujrwanala", Country: "India", other_columns },
{ City: "Gujranwala", Country: "Pakistan", other_columns }
]
The output should be:
list = [
{ City: "Gujranwala", Country: "Pakistan", other_columns },
{ City: "Gujrwanala", Country: "India", other_columns }
]
You can first extract the key-value pairs from the dicts and then remove duplicates by using a set. So you can do something like this:
Convert dicts into a list of dict_items:
dict_items = [tuple(d.items()) for d in lst] # they need to be tuples, otherwise you wouldn't be able to cast the list to a set
Deduplicate:
deduplicated = set(dict_items)
Convert the dict_items back to dicts:
back_to_dicts = [dict(i) for i in deduplicated]
I'm sure there are many other and probably better approaches to this problem, but you can use:
l = [
{ "City": "Gujranwala", "Country": "Pakistan" },
{ "City": "Gujrwanala", "Country": "India" },
{ "City": "Gujranwala", "Country": "Pakistan" }
]
ll, v = [], set()
for d in l:
k = d["City"] + d["Country"]
if not k in v:
v.add(k)
ll.append(d)
print(ll)
# [{'City': 'Gujranwala', 'Country': 'Pakistan'}, {'City': 'Gujrwanala', 'Country': 'India'}]`
Demo
We basically create a list with unique values containing the city and country that we use to verify if both values are already present on the final list.
One way to do this reduction is to have a dictionary with a unique key for every city, country combination. In my case I've just concatenated both those properties for the key which is a simple working solution.
We are using a dictionary here as the lookup on a dictionary happens in constant time, so the whole algorithm will run in O(n).
lst = [
{"City": "Gujranwala", "Country": "Pakistan"},
{"City": "Gujrwanala", "Country": "India"},
{"City": "Gujranwala", "Country": "Pakistan"}
]
unique = dict()
for item in lst:
# concatenate key
key = f"{item['City']}{item['Country']}"
# only add the value to the dictionary if we do not already have an item with this key
if not key in unique:
unique[key] = item
# get the dictionary values (we don't care about the keys now)
result = list(unique.values())
print(result)
Expected ouput:
[{'City': 'Gujranwala', 'Country': 'Pakistan'}, {'City': 'Gujrwanala', 'Country': 'India'}]
I'm trying to get a list of all keys in the nested level of my dictionary.
My dictionary resembles:
my_dict= {
'DICT':{
'level_1a':{
'level_2a':{}
},
'level_1b': {
'level_2b':{},
'level_2c':{}
}
}
My desired output should resemble:
['level_2a', 'level_2b', 'level_2c']
What I've tried:
[list(v) for k, v in json['DICT'].items()]
My current output:
[['level_2a'], ['level_2b', 'level_2c']]
I want my result to be fully flattened to a single-level list. I've tried flattening libraries but the result tends to appear as: ['level_2a', 'level_2blevel_2c'] which is incorrect. Not looking to make the code more complex by creating another method just to flatten this list.
Would appreciate some help, thank you!
Try:
my_dict = {
"DICT": {
"level_1a": {"level_2a": {}},
"level_1b": {"level_2b": {}, "level_2c": {}},
}
}
lst = [vv for v in my_dict["DICT"].values() for vv in v]
print(lst)
Prints:
['level_2a', 'level_2b', 'level_2c']
I want to create new dictionary by mapping list into dictionary, so the list item will be the key and the dictionary will be the value.
Students List :
[Student1,Student2,Student3]
dictionary:
{Math:90, CS:94, Since:89}
the expected result is one dictionary:
{
"Student1":{
Math:90
},
"Student2":{
CS:94
},
"Student3":{
Since:89
}
}
I tray this:
new_dic=dic()
new_dic = dic(zip(students,dic1)
output:
{
Student1:Math,
Student2:CS,
Student3:Since
}
but it give me unexpected result. also I try the solution here and it didn't works for me.
Use zip along with some modification to reproduce the inner dict structure
names = ["Student1", "Student2", "Student3"]
values = {"Math": 90, "CS": 94, "Since": 89}
result = {name: {course: val} for name, (course, val) in zip(names, values.items())}
Alternatively, you could use:
a = ['student1','student2','student3']
b = { "Math":90 , "CS":94, "Since":89 }
c = {k1: {k2: v} for (k1,k2,v) in zip(a, b.keys(), b.values())}
I have an XML file(~500 lines), that is converted to nested ordered dictionary in Python. I need that to be sorted according to values, but because it is nested so much and has lists in it, I am lost. I have searched for answers, trying to find a way to sort dictionary that is mixed with lists. But no luck so far.
This is the closest I have got. Python: Sort nested dictionary by value But because I have a key that has 2 subkeys "foo" and "bar", which have lists, which themselves have dictionaries inside, it isn't not quite what I need.
I would like to sort "foo" and "bar" according to "Date". Or return subdictionaries by "Date" values.
I have a loop that iterates through the subdictionary's list, but it does not sort it. I have tried changing it to fix it, but no changes. It also doesn't help, that lambda seems like magic to me.
for i in range(len(your_dict['History']['foo'])):
mine = OrderedDict(sorted(your_dict.items(), key=lambda x: x[1]["foo"][i]['Date']))
Short example of the dictionary at hand:
"History": {
"#version": "4.0",
"foo": [
{"code": "ID", "Date": "2018-07-09T15:31:09+03:00"},
{"Date": "2018-07-09T13:46:09+03:00"}
],
"bar": [
{"code": "ID", "Date": "2018-07-09T09:39:29+03:00"},
{"code": "ID", "Date": "2018-07-09T09:48:25+03:00"}
]
}
So how could "foo" and "bar" be sorted?
>>> s = dict((k,sorted(v, key=lambda x: x['Date'])) for k,v in d['History'].items() if type(v)==list)
>>> s['foo']
[{'Date': '2018-07-09T13:46:09+03:00'}, {'code': 'ID', 'Date': '2018-07-09T15:31:09+03:00'}]
>>> s['bar']
[{'code': 'ID', 'Date': '2018-07-09T09:39:29+03:00'}, {'code': 'ID', 'Date': '2018-07-09T09:48:25+03:00'}]
Explanation
The following list comprehension would return the dict items as key-value pairs
[(k,v) for k,v in d['History'].items()]
This would filter the key-value pairs and include them only when value is of type list
[(k,v) for k,v in d['History'].items() if type(v)==list]
# [('foo', [{'code': 'ID', 'Date': '2018-07-09T15:31:09+03:00'}, {'Date': '2018-07-09T13:46:09+03:00'}]), ('bar', [{'code': 'ID', 'Date': '2018-07-09T09:39:29+03:00'}, {'code': 'ID', 'Date': '2018-07-09T09:48:25+03:00'}])]
All we have to do now, is to sort each value based on date. sorted(v, key=lambda x: x['Date'])) would do that
Merging these in a single line, you get the above mentioned one-liner
Using sorted with lambda
Ex:
d = {"History": {
"#version": "4.0",
"foo": [
{"code": "ID", "Date": "2018-07-09T15:31:09+03:00"},
{"Date": "2018-07-09T13:46:09+03:00"}
],
"bar": [
{"code": "ID", "Date": "2018-07-09T09:39:29+03:00"},
{"code": "ID", "Date": "2018-07-09T09:48:25+03:00"}
]
}
}
print(sorted(d["History"]["foo"], key=lambda k: k['Date']))
print(sorted(d["History"]["bar"], key=lambda k: k['Date']))
Output:
[{'Date': '2018-07-09T13:46:09+03:00'}, {'Date': '2018-07-09T15:31:09+03:00', 'code': 'ID'}]
[{'Date': '2018-07-09T09:39:29+03:00', 'code': 'ID'}, {'Date': '2018-07-09T09:48:25+03:00', 'code': 'ID'}]
The problem is you are trying to get .items, while you just want to sort a list, so no need for all that stuff, just get it straightforward like this:
for i in ('foo', 'bar'):
your_dict['History'][i] = sorted(your_dict['History][i], key=lambda x:x['date'])
I have the following simple data structures:
teams = [ { 'league_id': 1, 'name': 'Kings' }, { 'league_id': 1, 'name': 'Sharkls' }, { 'league_id': 2, 'name': 'Reign' }, { 'league_id': 2, 'name': 'Heat' } ]
leagues = [ { 'league_id': 1, 'name': 'League 1' }, { 'league_id': 2, 'name': 'League 2' } ]
And I have the following dict comprehension:
league_teams = { x['league_id']: [ t['name']
for t in teams if t['league_id'] == x ['league_id'] ]
for x in leagues }
Which yields:
{1: ['Kings', 'Sharkls'], 2: ['Reign', 'Heat']}
Is there a simpler way using itertools or something to get that dict? This feels a little cumbersome.
Here's an adaptation of Moinuddin Quadri's O(n+m) solution that catches the "empty league" case, and which incidentally does not require any modules to be imported. The dict output does double-duty as his league_ids set, and since it's pre-initialized, it does not need to be a collections.defaultdict:
output = { league['league_id']:[] for league in leagues }
for team in teams:
if team['league_id'] in output:
output[team['league_id']].append(team['name'])
print(output)
The output is:
{1: ['Kings', 'Sharkls'], 2: ['Reign', 'Heat']}
You do not need itertools here, instead collections.defaultdict is better choice. Complexity of your solution is O(n*m) whereas with defaultdict, it will be O(n+m).
You can achieve what you want like:
from collections import defaultdict
# create set to store `league_id` in `leagues`. Set holds unique
# values and also searching in set is faster than in normal list
leagues_id = set([item['league_id'] for item in leagues])
my_dict = defaultdict(list)
for item in teams:
if item['league_id'] in leagues_id:
my_dict[item['league_id']].append(item['name'])
where at the end my_dict will hold the value:
{1: ['Kings', 'Sharkls'], 2: ['Reign', 'Heat']}
Edit: In case you also want entry in my_dict for the league_id present in leagues, but not in teams, you need to explictly make entries like:
for leagues_id in leagues_ids:
_ = my_dict[leagues_id] # Will create empty list for such ids
Checking t['league_id'] == x['league_id'] looks not necessary.
You can simplify with:
import collections
league_teams = collections.defaultdict(list)
for t in teams:
league_teams[t['league_id']].append(t['name'])
If you really want itertools for that:
import itertools
league_teams = {k: [t['name'] for t in g]
for k, g in itertools.groupby(teams, key=lambda t: t['league_id'])}
But it will only work if the teams list is sorted.