mydict = {'a': {'name': 'Marco', 'gender': 'm', 'age': 38, 'info': 'teacher musician'}
'b': {'name': 'Daniela', 'gender': 'f', 'age': 28, 'info': 'student music'}
'c': {'name': 'Maria', 'gender': 'f', 'age': 25, 'info': 'doctor dance whatever'}}
How to select the records with an age below 30 and with the words including 'music' in the 'info'?
The results should be like:
newdict = {'b': {'name': 'Daniela', 'gender': 'f', 'age': 28, 'info': 'student music'}}
Simplest way is to use a dict-comp:
mydict = {'a': {'name': 'Marco', 'gender': 'm', 'age': 38, 'info': 'teacher musician'},
'b': {'name': 'Daniela', 'gender': 'f', 'age': 28, 'info': 'student music'},
'c': {'name': 'Maria', 'gender': 'f', 'age': 25, 'info': 'doctor dance whatever'}}
new_dict = {k:v for k,v in mydict.iteritems() if v['age'] < 30 and 'music' in v['info'].split()}
# {'b': {'info': 'student music', 'gender': 'f', 'age': 28, 'name': 'Daniela'}}
You can use the following comprehension :
>>> {d:k for d,k in mydict.items() if k['age']<30 and 'music' in k['info']}
{'b': {'info': 'student music', 'gender': 'f', 'age': 28, 'name': 'Daniela'}}
mydict.items() give you a tuple contain key ans value of dictionary at each loop , and you can chose the item that have the proper conditions !
Related
I have 2 lists
list1 = ["ben", "tim", "john", "wally"]
list2 = [18,12,34,55]
the output im looking for is this
[{'Name': 'ben', 'Age': 18, 'Name': 'tim', 'Age': 12, 'Name': 'john', 'Age': 34, 'Name': 'wally', 'Age': 55}]
As mentioned in the comments, you can't have duplicate keys in a dictionary; even your output snippet would just return [{'Name': 'wally', 'Age': 55}]
However, {k: v for k, v in zip(list1, list2)} will return
{'ben': 18, 'tim': 12, 'john': 34, 'wally': 55}
And [{'Name': n, 'Age': a} for n, a in zip(list1, list2)] will return
[{'Name': 'ben', 'Age': 18},
{'Name': 'tim', 'Age': 12},
{'Name': 'john', 'Age': 34},
{'Name': 'wally', 'Age': 55}]
Below is an example nested list of dictionaries. I want to order the lists by the number of points that Charlie has.
l = [[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20 },
{'Name': 'Charlie', 'Age': 30, 'Point': 10}],
[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20 },
{'Name': 'Charlie', 'Age': 30, 'Point': 30}],
[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20 },
{'Name': 'Charlie', 'Age': 30, 'Point': 20}]]
The output should look like this.
l = [[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20 },
{'Name': 'Charlie', 'Age': 30, 'Point': 10}],
[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20 },
{'Name': 'Charlie', 'Age': 30, 'Point': 20}],
[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20 },
{'Name': 'Charlie', 'Age': 30, 'Point': 30}]]
I think I should be able to use sorted() with the right arguments, but I'm not sure what the syntax would be.
sorted(l, key=lambda x: x[ ????? ])
Charlie is always the third dict in the sublists.
Use a lambda to search for Charlie's point in the nested lists:
l.sort(key=lambda lst: next(d.get('Point', 0) for d in lst if d.get('Name')=='Charlie'))
print(l)
If you want a new list:
out = sorted(l, key=lambda lst: next(d.get('Point', 0) for d in lst if d.get('Name')=='Charlie'))
Output:
[[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20},
{'Name': 'Charlie', 'Age': 30, 'Point': 10}],
[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20},
{'Name': 'Charlie', 'Age': 30, 'Point': 20}],
[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20},
{'Name': 'Charlie', 'Age': 30, 'Point': 30}]]
If Charlie is always third, you could use this:
sorted(l, key=lambda x: x[2]['Point'])
Otherwise, you'd want to use a helper function:
def get_charlie_points(lst):
for item in lst:
if item['Name'] == 'Charlie':
return item['Point']
return 0 # Replace this with the number you want if there is no Charlie, or raise an exception
sorted(l, key=get_charlie_points)
Very similar to #enke's answer, but using next to provide the default 0, rather than the get method.
s = sorted(l, key=lambda lst: next((d['Point'] for d in lst if d['Name'] == 'Charlie'), 0))
If Charlie is always third, keep it simple, use:
out = sorted(l, key=lambda x:x[2].get('Point', float('inf')))
NB. I used a default value of infinite if Charlie has no points, to push it to the end.
Output:
[[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20},
{'Name': 'Charlie', 'Age': 30, 'Point': 10}],
[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20},
{'Name': 'Charlie', 'Age': 30, 'Point': 20}],
[{'Name': 'Alice', 'Age': 40, 'Point': 80},
{'Name': 'Bob', 'Age': 20},
{'Name': 'Charlie', 'Age': 30, 'Point': 30}]]
I have a list of dictionaries in python like this;
l = [{'name': 'John', 'age': 23},
{'name': 'Steve', 'age': 35},
{'name': 'Helen'},
{'name': 'George'},
{'name': 'Jessica', 'age': 23}]
What I am trying to achieve here is reorder the elements of l in such a way that each entry containing the key age move to the end of the list like this;
End result:
l = [{'name': 'Helen'},
{'name': 'George'},
{'name': 'Jessica', 'age': 23},
{'name': 'John', 'age': 23},
{'name': 'Steve', 'age': 35}]
How can I do this?
You can sort the list:
l.sort(key=lambda d: 'age' in d)
The key returns either True or False, based on the presence of the 'age' key; True is sorted after False. Python's sort is stable, leaving the rest of the relative ordering intact.
Demo:
>>> from pprint import pprint
>>> l = [{'name': 'John', 'age': 23},
... {'name': 'Steve', 'age': 35},
... {'name': 'Helen'},
... {'name': 'George'},
... {'name': 'Jessica', 'age': 23}]
>>> l.sort(key=lambda d: 'age' in d)
>>> pprint(l)
[{'name': 'Helen'},
{'name': 'George'},
{'age': 23, 'name': 'John'},
{'age': 35, 'name': 'Steve'},
{'age': 23, 'name': 'Jessica'}]
If you also wanted to sort by age, then retrieve the age value and return a suitable stable sentinel for those entries that do not have an age, but which will be sorted first. float('-inf') will always be sorted before any other number, for example:
l.sort(key=lambda d: d.get('age', float('-inf')))
Again, entries without an age are left in their original relative order:
>>> l.sort(key=lambda d: d.get('age', float('-inf')))
>>> pprint(l)
[{'name': 'Helen'},
{'name': 'George'},
{'age': 23, 'name': 'John'},
{'age': 23, 'name': 'Jessica'},
{'age': 35, 'name': 'Steve'}]
Here is my problem. I got this
{'Ciaran Johnson': {'PB': 58.2,
'Gender': 'M',
'Age': 6,
'Event': 'IM',
'Name': 'Ciaran Johnson'},
'Joan Pine': {'PB': 44.0,
'Gender': 'F',
'Age': 6,
'Event': 'FS',
'Name': 'Joan Pine'},
'Eric Idle': {'PB': 57.2,
'Gender': 'M',
'Age': 6,
'Event': 'IM',
'Name': 'Eric Idle'},
'Kirsty Laing': {'PB': 58.2,
'Gender': 'F',
'Age': 6,
'Event': 'IM',
'Name': 'Kirsty Laing'}}
and I have to sort it firsty by gender,then event and lastle time(PB -the fastest to be first)
I have this [dict] and I have to sort it...
You cannot sort a dict, since standard dictionaries are unordered. You can, however, use an OrderedDict:
In [2]: from collections import OrderedDict
In [3]: sd = OrderedDict(sorted(d.items(), key=lambda (k,v): (v['Gender'], v['Event'], v['PB'])))
In [4]: sd
Out[4]: OrderedDict([('Joan Pine', {'PB': 44.0, 'Gender': 'F', 'Age': 6, 'Event': 'FS', 'Name': 'Joan Pine'}), ('Kirsty Laing', {'PB': 58.2, 'Gender': 'F', 'Age': 6, 'Event': 'IM', 'Name': 'Kirsty Laing'}), ('Eric Idle', {'PB': 57.2, 'Gender': 'M', 'Age': 6, 'Event': 'IM', 'Name': 'Eric Idle'}), ('Ciaran Johnson', {'PB': 58.2, 'Gender': 'M', 'Age': 6, 'Event': 'IM', 'Name': 'Ciaran Johnson'})])
You can't sort a dictionary in Python, they are inherently unordered.
You can sort the keys() though, which creates a list, and then use that list to access the elements in a fake ordered way.
Try this
>>> for k,v in sorted(spam.items(),key=lambda k:(k[1]['Gender'],k[1]['Age'],k[1]['PB'])):
print(k,v)
Joan Pine {'PB': 44.0, 'Gender': 'F', 'Age': 6, 'Event': 'FS', 'Name': 'Joan Pine'}
Kirsty Laing {'PB': 58.2, 'Gender': 'F', 'Age': 6, 'Event': 'IM', 'Name': 'Kirsty Laing'}
Eric Idle {'PB': 57.2, 'Gender': 'M', 'Age': 6, 'Event': 'IM', 'Name': 'Eric Idle'}
Ciaran Johnson {'PB': 58.2, 'Gender': 'M', 'Age': 6, 'Event': 'IM', 'Name': 'Ciaran Johnson'}
>>>
How to convert list of dict to dict. Below is the list of dict
data = [{'name': 'John Doe', 'age': 37, 'sex': 'M'},
{'name': 'Lisa Simpson', 'age': 17, 'sex': 'F'},
{'name': 'Bill Clinton', 'age': 57, 'sex': 'M'}]
to
data = {'John Doe': {'name': 'John Doe', 'age': 37, 'sex': 'M'},
'Lisa Simpson': {'name': 'Lisa Simpson', 'age': 17, 'sex': 'F'},
'Bill Clinton': {'name': 'Bill Clinton', 'age': 57, 'sex': 'M'}}
A possible solution using names as the new keys:
new_dict = {}
for item in data:
name = item['name']
new_dict[name] = item
With python 3.x you can also use dict comprehensions for the same approach in a more nice way:
new_dict = {item['name']:item for item in data}
As suggested in a comment by Paul McGuire, if you don't want the name in the inner dict, you can do:
new_dict = {}
for item in data:
name = item.pop('name')
new_dict[name] = item
With python 3.3 and above, you can use ChainMap
A ChainMap groups multiple dicts or other mappings together to create
a single, updateable view. If no maps are specified, a single empty
dictionary is provided so that a new chain always has at least one
mapping.
from collections import ChainMap
data = dict(ChainMap(*data))
If the dicts wouldnt share key, then you could use:
dict((key,d[key]) for d in data for key in d)
Probably its better in your case to generate a dict with lists as values?
newdict={}
for k,v in [(key,d[key]) for d in data for key in d]:
if k not in newdict: newdict[k]=[v]
else: newdict[k].append(v)
This yields:
>>> newdict
`{'age': [37, 17, 57], 'name': ['John Doe', 'Lisa Simpson', 'Bill Clinton'], 'sex': ['M', 'F', 'M']}`
Try this approach:
{key: val} for k in data for key, val in k.items())
Let's not over complicate this:
simple_dictionary = dict(data[0])
Perhaps you want the name to be the key? You don't really specify, since your second example is invalid and not really meaningful.
Note that my example removes the key "name" from the value, which may be desirable (or perhaps not).
data = [{'name': 'John Doe', 'age': 37, 'sex': 'M'},
{'name': 'Lisa Simpson', 'age': 17, 'sex': 'F'},
{'name': 'Bill Clinton', 'age': 57, 'sex': 'M'}]
newdata = {}
for entry in data:
name = entry.pop('name') #remove and return the name field to use as a key
newdata[name] = entry
print newdata
##{'Bill Clinton': {'age': 57, 'sex': 'M'},
## 'John Doe': {'age': 37, 'sex': 'M'},
## 'Lisa Simpson': {'age': 17, 'sex': 'F'}}
print newdata['John Doe']['age']
## 37
import pandas as pd
data = [{'name': 'John Doe', 'age': 37, 'sex': 'M'},
{'name': 'Lisa Simpson', 'age': 17, 'sex': 'F'},
{'name': 'Bill Clinton', 'age': 57, 'sex': 'M'}]
print(pd.DataFrame(data).to_dict())
My 5 cents, didn't like any of answers:
from functools import reduce
collection = [{'hello': 1}, {'world': 2}]
answer = reduce(lambda aggr, new: aggr.update(new) or aggr, collection, {})
Just in case you wanted a functional alternative (also assuming the names are wanted as the new keys), you could do
from toolz.curried import *
data = [{'name': 'John Doe', 'age': 37, 'sex': 'M'},
{'name': 'Lisa Simpson', 'age': 17, 'sex': 'F'},
{'name': 'Bill Clinton', 'age': 57, 'sex': 'M'}]
newdata = pipe(data,
map(lambda x: {x['name']: dissoc(x, 'name')}),
lambda x: merge(*x)
)
print(newdata)