Python dictionary groupby key then count other key values - python-3.x

Assuming I have 4 dictionaries
x = {'id': 1, 'addressed_to': 2, 'status': 'open'}
y = {'id': 2, 'addressed_to': 2, 'status': 'open'}
z = {'id': 3, 'addressed_to': 2, 'status': 'closed'}
z = {'id': 4, 'addressed_to': 3, 'status': 'open'}
I am interested in getting something like this
result = [{'addressed_to': 2, 'open': 2, 'closed':1},{'addressed_to':3 , 'open': 1, 'closed':0} ]
How can I archive this in python3?

One possible answer is to move the dictionaries to a list and iterate thru them to get the required answers. Sample code below. The keys for the result dictionary are values of addressed_to
data_list = {"statsdata": [
{'id': 1, 'addressed_to': 2, 'status': 'open'},
{'id': 2, 'addressed_to': 2, 'status': 'open'},
{'id': 3, 'addressed_to': 2, 'status': 'closed'},
{'id': 4, 'addressed_to': 3, 'status': 'open'}
] }
p_result = {}
def checkItem(item):
if item["status"] == "open":
p_result[item["addressed_to"]]["open"] += 1
if item["status"] == "closed":
p_result[item["addressed_to"]]["closed"] += 1
for item in data_list["statsdata"]:
if item["addressed_to"] not in p_result:
p_result[item["addressed_to"]] = {'open':0, 'closed': 0}
checkItem(item)
else:
checkItem(item)
print(p_result)
Result will appear as
{2: {'open': 2, 'closed': 1}, 3: {'open': 1, 'closed': 0}}

Related

python converting a List of Tuples into a Dict with external keys

I have a list of tuples like this
[
(1,'a'),
(2,'b'),
(3,'c'),
(4,'d'),
(5,'e')
]
The result should be a list of dictionaries
[
{'id': 1, 'label': 'a'},
{'id': 2, 'label': 'b'},
{'id': 3, 'label': 'c'},
{'id': 4, 'label': 'd'},
{'id': 5, 'label': 'e'}
]
I'm using python 3.6
The first value in every tuple is named as 'id' and the second value in every tuple is named as 'label'.
I want to get the above result without using loop since the data will be huge.
Is there any built-in method to achieve my result?
Using map
Ex:
data = [
(1,'a'),
(2,'b'),
(3,'c'),
(4,'d'),
(5,'e')
]
keys = ["id", 'label']
print(list(map(lambda x: dict(zip(keys, x)), data)))
#List comprehension
#print([dict(zip(keys, i)) for i in data])
Output:
[{'id': 1, 'label': 'a'},
{'id': 2, 'label': 'b'},
{'id': 3, 'label': 'c'},
{'id': 4, 'label': 'd'},
{'id': 5, 'label': 'e'}]
A simple comprehension will do:
l = [
(1,'a'),
(2,'b'),
(3,'c'),
(4,'d'),
(5,'e')
]
results = [{"id" : id, "label": label} for id, label in l]
If your data is too big you can use a generator (so it will be lazily evaluated):
results = ({"id" : id, "label": label} for id, label in l)
Or use map:
results = map(lambda x: {"id" : x[0], "label": x[1]}, l)
import itertools as it # pip install itertools
ids=[] # lists
a=[
(1,'a'), # input
(2,'b'),
(3,'c'),
(4,'d'),
(5,'e')
]
for i, j in a :
# for j in i:
di=("id", i ,"label", j)
ids.append(dict(it.zip_longest(*[iter(di)] * 2, fillvalue="")))
print(ids)
output :
[{'id': 5, 'label': 'e'}, {'id': 5, 'label': 'e'}, {'id': 5, 'label': 'e'}, {'id': 5, 'label': 'e'}, {'id': 5, 'label': 'e'}]

Match values of two dictionaries and update list inside one of the dictionaries with matching key value pair

Hello have tried to figure this out for some time without much luck so any help is greatly appreciated.
Trying to match the titles of the aa list of dictionaries to the titled of the bb list of dictionaries and update the aa list of dictionaries to a key value combination
aa = [{'link': 'www.home.com', 'title': ['one', 'two', 'three']}, {'link': 'www.away.com', 'title':['two', 'three']}]
bb = [{'id': 1, 'title' :'one'},{'id': 2, 'title': 'two'}, {'id': 3, 'title': 'three'}]
result = [{'link':'www.home.com', 'title':[{'one': 1, 'two': 2, 'three': 3}]}, {'link': 'www.away.com', 'title':[{'two': 2, 'three': 3}]}
]
The result is:
result = [{'link': 'www.home.com', 'title': [{'one': 1, 'two': 2, 'three': 3}]}, {'link': 'www.away.com', 'title': [{'two': 2, 'three': 3}]}]
Refer my code as below:
from copy import deepcopy
aa = [{'link': 'www.home.com', 'title': ['one', 'two', 'three']}, {'link': 'www.away.com', 'title':['two', 'three']}]
bb = [{'id': 1, 'title' :'one'},{'id': 2, 'title': 'two'}, {'id': 3, 'title': 'three'}]
titleids = {}
for b in bb:
titleids[b['title']] = b['id']
result = deepcopy(aa)
for a in result:
a['title'] = [{title:titleids[title] for title in a['title']}]
print(result)
b1={k["title"]:k["id"] for k in bb}
just to solve this example you will do:
[ {'link':l['link'],'title':{i:b1[i] for i in l["title"]}} for l in aa]
[{'link': 'www.home.com', 'title': {'one': 1, 'two': 2, 'three': 3}}, {'link': 'www.away.com', 'title': {'two': 2, 'three': 3}}]
Although if you had many other keys you will do:
[{i:({k:b1[k] for k in j} if i is 'title' else j) for i,j in l.items()} for l in aa]
[{'link': 'www.home.com', 'title': {'one': 1, 'two': 2, 'three': 3}}, {'link': 'www.away.com', 'title': {'two': 2, 'three': 3}}]

How to sort dictionaries objects at the list for comparing these lists in python 3

I am a newcomer in python. Give me please an advice.
I have two lists of JSON's object.
list1 = [{"A":"A1"},{"B":"B1"}]
list2 = [{"B":"B1"}, {"A":"A1"}]
I need to compare these lists at my test:
I try to do this with assert:
assert list1 == list2
But I got the following:
E AssertionError:
assert [{'A': 'A1'}, {'B', 'B1'}] == [{'B', 'B1'}, {'A': 'A1'}]
E At index 0 diff: {'A': 'A1'} != {'B', 'B1'}
How can I sort lists of objects before comparing these lists?
Thanks, guys. I have found the solution:
list1 =[{"name":"David","age":"25"},{"name":"John","age":"30"}]
list2=[{"name":"John","age":"30"},{"name":"David","age":"25"}]
sorted_list1 = sorted(list1, key = lambda item:item["name"])
sorted_list2 = sorted(list2, key = lambda item:item["name"])
assert sorted_list1 == sorted_list2
It works.
Here is a way to compare basic python objects at any depth.
Exclusion is tuple as it immutable
def sort_all( obj, nochange = False):
if nochange:
obj = obj.copy()
def _key(obj):
if isinstance(obj, dict):
sort_all(obj)
return str({k: obj[k] for k in sorted(obj, key = _key)})
if isinstance(obj, list):
sort_all(obj)
return str(obj)
if isinstance(obj, dict):
for k, v in obj.items():
sort_all(v)
if isinstance(obj, list):
obj.sort(key = _key)
return obj
this function sort all lists inside the object so the comparison become simple like that
l1 = [{1: 2}, {34: 5, 1: 2}, {2: 3, 'asd': [1, 3, 6, {'b': 55}]}, {4: 3, 'a': {34: 5, 1: 2}}]
l2 = [{2: 3, 'asd': [1, 3, 6, {'b': 55}]}, {4: 3, 'a': {1: 2, 34: 5}}, {1: 2}, {1: 2, 34: 5}]
l1 == l2
False
sort_all(l1)
[{34: 5, 1: 2}, {1: 2}, {2: 3, 'asd': [1, 3, 6, {'b': 55}]}, {4: 3, 'a': {34: 5, 1: 2}}]
sort_all(l2)
[{1: 2, 34: 5}, {1: 2}, {2: 3, 'asd': [1, 3, 6, {'b': 55}]}, {4: 3, 'a': {1: 2, 34: 5}}]
l1 == l2
True
or simply
sort_all(l1) == sort_all(l2)
by default function changes the object passed, if you want to avoid this, use nochange = True
l1 = [{1: 2}, {34: 5, 1: 2}, {2: 3, 'asd': [1, 3, 6, {'b': 55}]}, {4: 3, 'a': {34: 5, 1: 2}}]
l2 = [{2: 3, 'asd': [1, 3, 6, {'b': 55}]}, {4: 3, 'a': {1: 2, 34: 5}}, {1: 2}, {1: 2, 34: 5}]
sort_all(l1,nochange=True) == sort_all(l2,nochange=True)
True
l1 == l2
False
You can also compare class instances this way if they have str and eq methods implemented. For example
class CTest():
def __init__(self, param):
self.attr = param
def __str__(self):
return f"CTest_<{self.attr}>"
def __eq__(self, obj):
if not isinstance(obj, CTest):
return False
return self.attr == obj.attr
l1 = [CTest(1234),{1: 2}, {34: 5, 1: 2}, {2: 3, 'asd': [1, 3, 6, {'b': 55}, CTest(1),]}, {4: 3, 'a': {34: 5, 1: 2}}]
l2 = [{2: 3, 'asd': [1, 3, 6, CTest(1), {'b': 55}]}, {4: 3, 'a': {1: 2, 34: 5}}, {1: 2}, {1: 2, 34: 5},CTest(1234)]
l1 == l2
False
sort_all(l1) == sort_all(l2)
True

how to make collection of list from dict having same id?

[{'id': 6, 'name': 'Jorge'}, {'id': 6, 'name': 'Matthews'}, {'id': 6, 'name': 'Matthews'}, {'id': 7, 'name': 'Christine'}, {'id': 7, 'name': 'Smith'}, {'id': 7, 'name': 'Chris'}]
And i wanna make collection of list having same id like this
[{'id': 6, 'name': ['Jorge','Matthews','Matthews']}, {'id': 7, 'name': ['Christine','Smith','Chris']}]
L = [{'id': 6, 'name': 'Jorge'}, {'id': 6, 'name': 'Matthews'}, {'id': 6, 'name': 'Matthews'}, {'id': 7, 'name': 'Christine'}, {'id': 7, 'name': 'Smith'}, {'id': 7, 'name': 'Chris'}]
temp = {}
for d in L:
if d['id'] not in temp:
temp[d['id']] = []
temp[d['id']].append(d['name'])
answer = []
for k in sorted(temp):
answer.append({'id':k, 'name':temp[k]})
You can use itertools.groupby to group all the ids and then just extract the name for each element in the group:
In [1]:
import itertools as it
import operator as op
L = [{'id': 6, 'name': 'Jorge'}, ...]
_id = op.itemgetter('id')
[{'id':k, 'name':[e['name'] for e in g]} for k, g in it.groupby(sorted(L, key=_id), key=_id)]
Out[1]:
[{'id': 6, 'name': ['Jorge', 'Matthews', 'Matthews']},
{'id': 7, 'name': ['Christine', 'Smith', 'Chris']}]

Python: Retrieve result from inner dictionary

I'm fairly new to python and I don't know how can I retrieve a value from a inner dictionary:
This is the value I have in my variable:
variable = {'hosts': 1, 'key':'abc', 'result': {'data':[{'licenses': 2, 'id':'john'},{'licenses': 1, 'id':'mike'}]}, 'version': 2}
What I want to do is assign a new variable the number of licenses 'mike' has, for example.
Sorry for such a newbie, and apparent simple question, but I'm only using python for a couple of days and need this functioning asap. I've search the oracle (google) and stackoverflow but haven't been able to find an answer...
PS: Using python3
Working through it and starting with
>>> from pprint import pprint
>>> pprint(variable)
{'hosts': 1,
'key': 'abc',
'result': {'data': [{'id': 'john', 'licenses': 2},
{'id': 'mike', 'licenses': 1}]},
'version': 2}
First, let's get to the result dict:
>>> result = variable['result']
>>> pprint(result)
{'data': [{'id': 'john', 'licenses': 2}, {'id': 'mike', 'licenses': 1}]}
and then to its data key:
>>> data = result['data']
>>> pprint(data)
[{'id': 'john', 'licenses': 2}, {'id': 'mike', 'licenses': 1}]
Now, we have to scan that for the 'mike' dict:
>>> for item in data:
... if item['id'] == 'mike':
... print item['licenses']
... break
...
1
You could shorten that to:
>>> for item in variable['result']['data']:
... if item['id'] == 'mike':
... print item['licenses']
... break
...
1
But much better would be to rearrange your data structure like:
variable = {
'hosts': 1,
'version': 2,
'licenses': {
'john': 2,
'mike': 1,
}
}
Then you could just do:
>>> variable['licenses']['mike']
1
You can use nested references as follows:
variable['result']['data'][1]['licenses'] += 1
variable['result'] returns:
{'data':[{'licenses': 2, 'id':'john'},{'licenses': 1, 'id':'mike'}]}
variable['result']['data'] returns:
[{'licenses': 2, 'id':'john'},{'licenses': 1, 'id':'mike'}]
variable['result']['data'][1] returns:
{'licenses': 1, 'id':'mike'}
variable['result']['data'][1]['licenses'] returns:
1
which we then increment using +=1

Resources