How to Convert Dictionary Values to sets of Dictionaries - python

I am trying to solve some graph problems but i am stuck halfway. I have a python dictionary of sets, but i will like to convert the original dictionary values (which are sets) into a dictionary such that each value in the set becomes a key which would have another value of 1. I think this is what is called a nested dictionary - i am not sure.
I looped through the dict.values(), assigned to a variable xxx, and used the dict.fromkeys(xxx, 1) code and it worked, but i am unable to integrate the result back into the original dictionary.
Here is an example of a dictionary:
d = {'35': {'1', '37', '36', '71'}, '37': {'1', '35'}}
I want the output to look like:
d = {35: {1 : 1, 37 : 1, 36 : 1, 71 : 1}, 37: {1 : 1, 35 : 1}}
if you notice, the original dictionary values have become dictionaries of their own, and the apostrophes ('') are off.
Can someone assist me please, or give me pointers. Thank you

You just need a little bit of list comprehension:
def convert(input):
return {key: {val: 1 for val in vals} for key, vals in input.items()}
print(convert({'35': {'1', '37', '36', '71'}, '37': {'1', '35'}}))
# {'35': {'1': 1, '37': 1, '36': 1, '71': 1}, '37': {'1': 1, '35': 1}}

You are almost there. Just wrap keys and values with int:
{int(k):dict.fromkeys(map(int, v), 1) for k, v in d.items()}
Output:
{35: {37: 1, 71: 1, 36: 1, 1: 1}, 37: {35: 1, 1: 1}}

Related

How to get individual fields in list of dictionary

I have a list of dictionaries called dictList that has data like so:
[{'id': '5', 'total': '39'}, {'id': '5', 'total': '43'}].
I am trying to create a new dictionary that uses the id as the key and total as the value.
So have tried this:
keys = [d['id'] for d in dictList]
values = [d['total'] for d in dictList]
new_dict[str(keys)]= values
However the output is: {"['5', '5']": [39, 43]}
I am not sure what is going on, I am just trying to get the id and the respective total like 5, 39 and 5, 43 in to new_dict.
EDIT:
Please note that dictList contains all the products with ID 5. There are other fields, but I didn't include them.
One approach:
data = [{'id': '5', 'total': '39'}, {'id': '5', 'total': '43'}]
res = {}
for d in data:
key = d["id"]
if key not in res:
res[key] = 0
res[key] += int(d["total"])
print(res)
Output
{'5': 82}
Alternative using collections.defaultdict:
from collections import defaultdict
data = [{'id': '5', 'total': '39'}, {'id': '5', 'total': '43'}]
res = defaultdict(int)
for d in data:
key = d["id"]
res[key] += int(d["total"])
print(res)
Output
defaultdict(<class 'int'>, {'5': 82})
Use sorted and itertools.groupby to group by the 'id' key of each list element:
import itertools
dictList = [{'id': '5', 'total': '39'}, {'id': '10', 'total': '10'},
{'id': '5', 'total': '43'}, {'id': '10', 'total': '22'}]
groups = itertools.groupby(sorted(dictList, key=lambda item: item['id'])
, key=lambda item: item['id'])
Next, take the sum of each group:
product_totals = {
key: sum(int(item['total']) for item in grp)
for key, grp in groups
}
Which gives:
{'10': 32, '5': 82}
If you have lots of such entries, you could consider using pandas to create a dataframe. Pandas has vectorized methods that help you crunch numbers faster. The idea behind finding the sum of totals is the same, except in this case we don't need to sort because pandas.groupby takes care of that for us
>>> import pandas as pd
>>> df = pd.DataFrame(dictList)
>>> df['total'] = df['total'].astype(int)
>>> df
id total
0 5 39
1 10 10
2 5 43
3 10 22
>>> df.groupby('id').total.sum()
id
10 32
5 82
Name: total, dtype: int32
>>> df.groupby('id').total.sum().as_dict()
{'10': 32, '5': 82}
Although I'm not sure what you are trying to do, try this:
for d in dictlist:
if new_dict[d["id"]]:
new_dict[d["id"]] += d["total"]
else:
new_dict[d["id"]] = d["total"]

Finding all keys in a dictionary for which one or more value is repeated more than once in another dictionary

I have two dictionaries:
dict_1 = {'mother': ['mother', 'mom', 'mum', 'mommy', 'mummy', 'mamma', 'momma', 'ma', 'mama'],
'boy': ['boy', 'guy', 'dude', 'lad', 'son', 'schoolboy', 'young man'],
'girl': ['girl', 'daughter', 'lass', 'schoolgirl', 'young lady'],
'kitchen': ['kitchen'],
'exterior': ['exterior', 'outside', 'outdoor', 'outdoors'],
'car': ['car', 'vehicule', 'automobile'],
'water': ['water']
}
dict_2 = {'basket': 2,
'car' : 8,
'juice': 1,
'window': 6,
'outside': 2,
'oudoor': 4,
'road': 1,
'mom': 5,
'mother': 2,
'song': 1,
'vehicule': 1,
'fruits': 6
}
I'm looking for a way to find all keys in dict_1 for which one or more value is a key that has a value > 1 in dict_2 and the number of times a value associated with these keys is repeated in dict_2. Once I've found this, I would like to get another dictionary in which the keys are dict_1's keys (in this case, 'mother' and 'exterior') that are repeated more than once and the values are the number of times a value associated with these keys is repeated in dict_2 (in this case, 7 for 'mother' and 6 for 'exterior').
With the dictionaries I have, I would like my new dictionary to look something like this:
dict_final = {'mother': 7,
'exterior': 6,
'car': 9
}
Is there a way to do that in Python?
One approach:
res = {}
for k, vs in dict_1.items():
total = sum(dict_2.get(v, 0) for v in vs)
if total > 0:
res[k] = total
print(res)
Output
{'mother': 7, 'exterior': 6, 'car': 9}
As an alternative consider a dictionary comprehension (with a walrus operator in the mix):
res = {k: total for k, vs in dict_1.items() if (total := sum(dict_2.get(v, 0) for v in vs)) > 0}

How to order a dictionary based on the keys? [duplicate]

This question already has answers here:
How do I sort a dictionary by key?
(32 answers)
Closed 2 years ago.
I have a dictionary that the keys representing the item and the value represent count of that.
for example in below dictionary:
dict= {'11': 4, '0': 2, '65': 1, '88': 1, '12': 1, '13': 1}
'11' occurred 4 times
'0' occurred 2 times
'65' occurred 1 time
How to order the dictionary that dict.keys() are descending or ascending?
The Ideal out put will be either
dict={'0':2,'11':4,'12':1,'13':1,'65':1,'88':1}
or
dict={'88':1,'65':1,'13':1,'12':1,'11':4,'0':2}
Any help would be appreciated
score = {'eng': 33, 'sci': 85, 'math': 60}
You can do it like this...
score_sorted = sorted(score.items(), key=lambda x:x[0])
If you wanna sort it by val, then score_sorted = sorted(score.items(), key=lambda x:x[1]). You can add reverse=True to change order as well.
Contrary to older posts dictionaries are no longer unordered and can be sorted since CPython 3.6 (unofficially, as a C implementation detail) and Python 3.7 (officially).
To sort by key use a dictionary comprehension to build a new dictionary in the order desired. If you want to sort by string collation order, use the following, but note that '2' comes after '11' as a string:
>>> d = {'11': 4, '2': 2, '65': 1, '88': 1, '12': 1, '13': 1}
>>> {k:d[k] for k in sorted(d)}
{'11': 4, '12': 1, '13': 1, '2': 2, '65': 1, '88': 1}
To order by integer value, pass a key function that converts the string to an integer:
>>> {k:d[k] for k in sorted(d,key=lambda x: int(x))}
{'2': 2, '11': 4, '12': 1, '13': 1, '65': 1, '88': 1}
Or reversed you can use reverse=True or just negate the integer:
>>> {k:d[k] for k in sorted(d,key=lambda x: -int(x))}
{'88': 1, '65': 1, '13': 1, '12': 1, '11': 4, '2': 2}
With older Python versions convert the dictionary to a list with list(d.items()) and use similar sorting.
myDict= {'11': 4, '0': 2, '65': 1, '88': 1, '12': 1, '13': 1}
sortDict = {}
for i in sorted(myDict.keys()) :
sortDict[i] = myDict[i]
print(sortDict)
dict= {'11': 4, '0': 2, '65': 1, '88': 1, '12': 1, '13': 1}
You can try dictionary comprehension like this
sorted_dict={k:dict[k] for k in sorted(dict)}
print(sorted_dict)
Note: Don't use dict as a variable name as it is already a built-in function.
your_dict = {'11': 4, '0': 2, '65': 1, '88': 1, '12': 1, '13': 1} is better.
You can use sample_list = list(your_dict.items()) which convets the given dict into a list.
In the Python Dictionary, items() method is used to return the list with all dictionary keys with values.
Use sample_list.sort() to sort the list.
To reverse the list, use reverse = True
sample_list = list(your_dict.items())
sample_list.sort(reverse = True)
Then use dict = dict(sample_list) to convert it into a dictionary and print it out.

Fill dictionary with value from the same row, but different column

Lately I've been trying to map some values, so I'm trying to create a dictionary to do so. The odd thing is my DataFrame has a column made of lists, and DataFrames are always a bit awkward with lists. The DataFrame has the following structure:
rules procedure
['10','11','12'] 1
['13','14'] 2
['20','21','22','24'] 3
So I want to create a dictionary that maps '10' to 1, '14' to 2, and so on. I tried the following:
dicc=dict()
for j in df['rules']:
for i,k in zip(j,df.procedure):
dicc[i]=k
But that isn't making it. Probably something to do with indexes. What am I missing?
Edit: I'm trying to create a dictionary that maps the values '10', '11', '12' to 1; '13','14' to 2; '20','21','22','24' to 3, so if I typedicc['10'] I get 1, if I typedicc['22'] I get 3. Obviously, the actual DataFrame is quite bigger and I can't do it manually.
You can do it like this:
import pandas as pd
data = [[['10', '11', '12'], 1],
[['13', '14'], 2],
[['20', '21', '22', '24'], 3]]
df = pd.DataFrame(data=data, columns=['rules', 'procedure'])
d = {r : p for rs, p in df[['rules', 'procedure']].values for r in rs}
print(d)
Output
{'20': 3, '10': 1, '11': 1, '24': 3, '14': 2, '22': 3, '13': 2, '12': 1, '21': 3}
Notes:
The code {r : p for rs, p in df[['rules', 'procedure']].values for r
in rs} is a dictionary comprehension, the dictionary counterpart of
list.
The df[['rules', 'procedure']].values is equivalent to
zip(df.rules, df.procedure) it outputs a pair of list, int. So the
rs variable is a list and p is an integer.
Finally you iterate over the values of rs using the second for loop
UPDATE
As suggested for #piRSquared you can use zip:
d = {r : p for rs, p in zip(df.rules, df.procedure) for r in rs}
Help from cytoolz
from cytoolz.dicttoolz import merge
merge(*map(dict.fromkeys, df.rules, df.procedure))
{'10': 1,
'11': 1,
'12': 1,
'13': 2,
'14': 2,
'20': 3,
'21': 3,
'22': 3,
'24': 3}
Note
I updated my post to mimic how #jpp passed multiple iterables to map. #jpp's answer is very good. Though I'd advocate for upvoting all useful answers, I wish I could upvote their answer again (-:
Using collections.ChainMap:
from collections import ChainMap
res = dict(ChainMap(*map(dict.fromkeys, df['rules'], df['procedure'])))
print(res)
{'10': 1, '11': 1, '12': 1, '13': 2, '14': 2,
'20': 3, '21': 3, '22': 3, '24': 3}
For many uses, the final dict conversion is not necessary:
A ChainMap class is provided for quickly linking a number of
mappings so they can be treated as a single unit. It is often much
faster than creating a new dictionary and running multiple update()
calls.
See also What is the purpose of collections.ChainMap?
You may check flatten the list
dict(zip(sum(df.rules.tolist(),[]),df.procedure.repeat(df.rules.str.len())))
Out[60]:
{'10': 1,
'11': 1,
'12': 1,
'13': 2,
'14': 2,
'20': 3,
'21': 3,
'22': 3,
'24': 3}
using itertools.chain and DataFrame.itertuples:
dict(
chain.from_iterable(
((rule, row.procedure) for rule in row.rules) for row in df.itertuples()
)
)

dictionary update sequence element #0 has length 3; 2 is required when updating with a tuple

I have a problem with a dictionary that I want to split into two others.
dico={'GA1': {'main': 1, 'middle': 1, 'sub': 1},
'GA2': {'main': 1, 'middle': 1, 'sub': 2},
'GA3': {'main': 1, 'middle': 1, 'sub': 3},
'GA4': {'main': 1, 'middle': 1, 'sub': 4},
'GA5': {'main': 1, 'middle': 1, 'sub': 5},
'GA6': {'main': 1, 'middle': 1, 'sub': 6},
'GA7': {'main': 1, 'middle': 1, 'sub': 7},
'GA8': {'main': 1, 'middle': 1, 'sub': 8},
'GA9': {'main': 1, 'middle': 1, 'sub': 9},
'GA10': {'main': 1, 'middle': 1, 'sub': 10}}
I want to put GA2 and GA6 to GA10 in a dictionary d1 and GA1 and GA3 to GA5 in a dictionary d2.
When I transform it into a list, I end up with tupples like,
list(dico.items())[0]
which gives ('GA1', {'main': 1, 'middle': 1, 'sub': 1})
When I want to set this into my new dictionary,
d2 = {}
d2.update(list(dico.items())[0])
I end up with "builtins.ValueError: dictionary update sequence element #0 has length 3; 2 is required"
Is a dictionary an invalid format for a tuple element ?
Thanks for your help
Alexandre
Did you mean this?
d2.update([list(dico.items())[0]])
You can initialise a dictionary with a list of tuples. You were providing only a single tuple, not inside a list. Use the [] to initialise a singleton list and pass that:
{'GA10': {'middle': 1, 'main': 1, 'sub': 10}}
Also, doing list(dico.items()) and then taking the 0th element is wasteful. If you can, consider changing your approach to your problem.
d1 = { k:dico[k] for k in ['GA2','GA6','GA10'] }
print (d1)
Output:
{'GA2': {'main': 1, 'middle': 1, 'sub': 2}, 'GA6': {'main': 1, 'middle': 1, 'sub': 6}, 'GA10': {'main': 1, 'middle': 1, 'sub': 10}}
Create a list of the keys you want, then use a dict comprehension. Code below creates a dictionary, d2, with GA1, GA8 and GA9, key-value pairs.
newkeys = ['GA1', 'GA8', 'GA9']
d2 = {k: dico[k] for k in set(newkeys) & set(dico.keys())}
see Filter dict to contain only certain keys? for more info

Categories

Resources