I have a data set as below
tmp_dict = {
'a': ?,
'b': ?,
'c': ?,
}
and I have a data is a list of dictionaries like
tmp_list = [tmp_dict1, tmp_dict2, tmp_dict3....]
and I found some of dictionaries are not perfectly have keys about 'a','b','c'.
How do I check and fill the key is not existing
You could try something like this:
# List of keys to look for in each dictionary
dict_keys = ['a','b','c']
# Generate the dictionaries for demonstration purposes only
tmp_dict1 = {'a':[1,2,3], 'b':[4,5,6]}
tmp_dict2 = {'a':[7,8,9], 'b':[10,11,12], 'c':[13,14,15]}
tmp_dict3 = {'a':[16,17,18], 'c':[19,20,21]}
# Add the dictionaries to a list as per OP instructions
tmp_list = [tmp_dict1, tmp_dict2, tmp_dict3]
#--------------------------------------------------------
# Check for missing keys in each dict.
# Print the dict name and keys missing.
# -------------------------------------------------------
for i, dct in enumerate(tmp_list, start=1):
for k in dict_keys:
if dct.get(k) == None:
print(f"tmp_dict{i} is missing key:", k)
OUTPUT:
tmp_dict1 is missing key: c
tmp_dict3 is missing key: b
I think you want this.
tmp_dict = {'a':1, 'b': 2, 'c':3}
default_keys = tmp_dict.keys()
tmp_list = [{'a': 1}, {'b': 2,}, {'c': 3}]
for t in tmp_list:
current_dict = t.keys()
if default_keys - current_dict:
t.update({diff: None for diff in list(default_keys-current_dict)})
print(tmp_list)
Output:
[{'a': 1, 'c': None, 'b': None}, {'b': 2, 'a': None, 'c': None}, {'c': 3, 'a': None, 'b': None}]
You can compare the keys in the dictionary with a set containing all the expected keys.
for d in tmp_list:
if set(d) != {'a', 'b', 'c'}:
print(d)
Related
I want to get a possible structure with all possible keys of a single field in the database, which is stored in JSON(dict) format. The structure in my task is very important, so storing in list is not suitable.There can be many levels of nesting much more than two.
This example:
dicts = {'a':1, 'b':2, 'c':{'in_c1': 2}}, \
{'a':1, 'd':2, 'c':{'dict_in_c2': {'v': 2}}},\
{'e':57}
Should return:
{'a': 1, 'b':2, 'c': {'in_c1': 2, 'dict_in_c2': {'v': 2}}, 'd': 2, 'e': 57}
The text(values of keys) is not important to me, it is better to replace it with something similar like none or an empty string.
How I can do this?
This might not be able to handle all cases, but it covers some basic cases.
I am assuming that
keys that have an integer value ( like a and b ) will NOT have any dictionary values.
keys that have a dictionary as value ( like c ) will NOT have any non-dictionary values. Also, the flattening has only been performed on the keys of the dictionary at the first level, but not on the nested levels.
Here is the code:
dicts = {'a':1, 'b':2, 'c':{'in_c1': 2}}, \
{'a':1, 'd':2, 'c':{'dict_in_c2': {'v': 2}}},\
{'e':57}
result = dict()
for dictionary in dicts:
for key, value in dictionary.items():
if not isinstance(value,dict):
result[key] = value
continue
if not result.get(key, None):
result[key] = dict()
for k, v in value.items():
result[key][k] = v
print(result)
Result -
{'b': 2, 'a': 1, 'c': {'dict_in_c2': {'v': 2}, 'in_c1': 2}, 'e': 57, 'd': 2}
If I understand your question correctly, you have a list of dicts, which you want to put it into a single dict.
If the list of dicts is:
dicts = [{'a':1, 'b':2, 'c':{'dict_in_c': 2}},
{'a':1, 'd':2, 'c':{'dict_in_c2': 2}},
{'e':57}]
Then you can do:
newdict={}
for eachdict in dicts:
for eachkey in eachdict.keys():
newdict[eachkey]=eachdict[eachkey]
newdict will be:
{'a': 1, 'b': 2, 'c': {'dict_in_c2': 2}, 'd': 2, 'e': 57}
I am trying to convert the list to a dictionary.
I have a list of list like this and some of the first values of mini lists are repeating:
list = [["DDS 500","A",300], ["DDS 500","B",100], ["AGB 850","C",250], ["AGB 850","B",350], ["UNI 100","D",900]]
The first value of mini lists will be key . Then, for each mini list second and third value will be the "value" for that key and the values also should be a dictionary. As a result, Final dictionary should be like this:
dict = { "DDS 500":{"A":300,"B":100}, "AGB 850":{"C":250,"B":350}, "UNI 100":{"D":900} }
You can use collections.defaultdict
from collections import defaultdict
lst= [["DDS 500","A",300], ["DDS 500","B",100], ["AGB 850","C",250], ["AGB 850","B",350], ["UNI 100","D",900]]
out=defaultdict(dict)
for k,ik,iv in lst:
out[k].update({ik:iv})
Output:
defaultdict(dict,
{'DDS 500': {'A': 300, 'B': 100},
'AGB 850': {'C': 250, 'B': 350},
'UNI 100': {'D': 900}})
you can use dict.setdefault if you do not want to import any module:
result = {}
for k1, k2, v in my_list:
result.setdefault(k1, {})[k2] = v
result
output:
{'DDS 500': {'A': 300, 'B': 100},
'AGB 850': {'C': 250, 'B': 350},
'UNI 100': {'D': 900}}
You could do it in two steps: 1) create the dictionary with all keys and and empty dictionary as value, 2) merge the values as dictionaries into each key:
lst = [["DDS 500","A",300], ["DDS 500","B",100], ["AGB 850","C",250], ["AGB 850","B",350], ["UNI 100","D",900]]
d = { k:dict() for k,*_ in lst }
for k,*v in lst: d[k].update(dict([v]))
output:
print(d)
# {'DDS 500': {'A': 300, 'B': 100}, 'AGB 850': {'C': 250, 'B': 350}, 'UNI 100': {'D': 900}}
I have a list which is structured as follows:
arr = [ ['a'],
['a','b'],
['a','x','y'],
['a','c'],
['a','c','a'],
['a','c','b'],
['a','c','b','a'],
['a','c','b','b'],
['a','d'],
['b'],
['b','c'],
['b','c','a'],
['b','c','b'],
['c','d'],
['c','d','e'],
['c','d','f'],
['c','d','f','a'],
['c','d','f','b'],
['c','d','f','b','a'],
]
As you would observe that the list has some unique elements and then following elements are building upon the unique element till a new unique element appears. These are supposed to categories and subcategories. So [a] , [b] , ['c','d'] are the broad level main categories and then there are further sub categories within sub categories based on the same priciple as above. Ideally I want the categories and sub categories as a dictionary. the end result should look something like:
{'a': ['a-b',
'a-x-y',
{'a-c':
['a-c-a',
{'a-c-b':
['a-c-b-a',
'a-c-b-b']
}]
}
],
'b' : ................
'c-d': ...............}
I may also be able to work with just the first level of sub-classification and discarding the rest altogether. In that case, the output would be:
{'a': ['a-b', 'a-x-y', 'a-c', 'a-d'], 'b': ['b-c'], 'c-d': ['c-d-e', 'c-d-f']}
I have written a code for the second scenario but I am not sure if this is a robust way to solve this:
def arrange(arr):
cat = {"-".join(arr[0]): ["-".join(arr[1])]}
main = 0
for i in range(2,len(arr)):
l = len(arr[main])
if arr[main] == arr[i][0:l]:
cat["-".join(arr[main])].append("-".join(arr[i]))
else:
cat["-".join(arr[i])] = []
main = i
for k,v in cat.items():
found = True
i = 0
while i < len(v)-1:
f_idx = i + 1
while v[i] in v[f_idx]:
v.pop(f_idx)
i += 1
return cat
Output-:
{'a': ['a-b', 'a-x-y', 'a-c', 'a-d'], 'b': ['b-c'], 'c-d': ['c-d-e', 'c-d-f']}
Please help me make this code better and or help me with a dictionary that has the complete structure where I have all the sub-classifications. Thanks
Finally , I believe I've what you describe as first level of sub-classification and discarding the rest altogether.
The trick was to create action based upon when an item in the list (keys) was not a sublist of subsequent items (values).
The same logic was used for removing duplicates.
from collections import defaultdict
#Function that compares two lists even with duplicate items
def contains_sublist(lst, sublst):
n = len(sublst)
return any((sublst == lst[i:i+n]) for i in xrange(len(lst)-n+1))
#Define default dict of list
aDict = defaultdict(list)
it = iter(arr)
#Format key
key = '-'.join(next(it))
s = list(key)
# Loop that collects keys if key is not sublist else values
for l in it:
if contains_sublist(l, s):
aDict[key].append(l)
else:
key = '-'.join(l)
s = l
#Loop to remove duplicate items based upon recurrance of sublist
it = iter(aDict.keys())
for k in it:
dellist = []
for s in aDict[k]:
for l in aDict[k]:
if l != s:
if contains_sublist(l, s):
if not l in dellist:
dellist.append(l)
for l in dellist:
try:
aDict[k].remove(l)
except ValueError:
pass
#Create final dict by concatenating list of list with '-'
finaldict = {k:[ '-'.join(i) for i in v ] for k,v in aDict.iteritems()}
Result:
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
>>> finaldict
{'a': ['a-b', 'a-x-y', 'a-c', 'a-d'], 'b': ['b-c'], 'c-d': ['c-d-e', 'c-d-f']}
>>>
You're describing a Trie.
Here's a very basic implementation:
def make_trie(words):
root = dict()
for word in words:
current_dict = root
for letter in word:
current_dict = current_dict.setdefault(letter, {})
current_dict[1] = 1
return root
trie = make_trie(arr)
print(trie)
# {'a': {1: 1, 'c': {'a': {1: 1}, 1: 1, 'b': {'a': {1: 1}, 1: 1, 'b': {1: 1}}}, 'b': {1: 1}, 'd': {1: 1}, 'x': {'y': {1: 1}}}, 'c': {'d': {1: 1, 'e': {1: 1}, 'f': {'a': {1: 1}, 1: 1, 'b': {'a': {1: 1}, 1: 1}}}}, 'b': {1: 1, 'c': {'a': {1: 1}, 1: 1, 'b': {1: 1}}}}
print(trie.get('a',{}).get('x',{}))
# {'y': {1: 1}}
This trie is just nested dicts, so it's easy to iterate over all the children of ['a', 'x'] or select all the dicts that have a max-depth of 2 for example.
1 is used for leaf words: for example if you have ['a', 'x', 'y'] as sub-array, but not ['a', 'x'].
There are more complete Trie libraries for Python, such as pygtrie.
I have a dictionary composed of {key: value}.
I select a set of keys from this dictionary.
I'd like to build a new dictionary with {keyA: set of all keys wich have the same value as keyA}.
I already have a solution: Is there a faster way to do it?
It seems very slow to me, and I imagine I'm not the only one in this case!
for key1 in selectedkeys:
if key1 not in seen:
seen.add(key1)
equal[key1] = set([key1])#egual to itself
for key2 in selectedkeys:
if key2 not in seen and dico[key1] == dico[key2]:
equal[key1].add(key2)
seen.update(equal[key1])
Try this
>>> a = {1:1, 2:1, 3:2, 4:2}
>>> ret_val = {}
>>> for k, v in a.iteritems():
... ret_val.setdefault(v, []).append(k)
...
>>> ret_val
{1: [1, 2], 2: [3, 4]}
def convert(d):
result = {}
for k, v in d.items(): # or d.iteritems() if using python 2
if v not in result:
result[v] = set()
result[v].add(k)
return result
or just use collections.defaultdict(set) if you are careful enough not to access any non key later :-)
So you want to create a dictionary that maps key to "the set of all keys which have the same value as key" for each selected key in a given source dictionary.
Thus, if the source dictionary is:
{'a': 1, 'b': 2, 'c': 1, 'd': 2, 'e': 3, 'f': 1, 'g': 3)
and the selected keys are a, b, and e, the result should be:
{'a': {'a', 'c', 'f'}, 'e': {'g', 'e'}, 'b': {'b', 'd'}}
One way to achieve this would be to use a defaultdict to build a value to key table, and then use that to build the required result from the specified keys:
from collections import defaultdict
def value_map(source, keys):
table = defaultdict(set)
for key, value in source.items():
table[value].add(key)
return {key: table[source[key]] for key in keys}
source = {'a': 1, 'b': 2, 'c': 1, 'd': 2, 'e': 3, 'f': 1, 'g': 3)
print(value_map(source, ['a', 'b', 'e']))
Output:
{'a': {'a', 'c', 'f'}, 'e': {'g', 'e'}, 'b': {'b', 'd'}}
Since you select a set of keys from the original dictionary. We can modify #Nilesh solution for your purpose.
a = {1:1, 2:1, 3:2, 4:2}
keys = [1, 3] # lets say this is the list of keys
ret_val = {}
for i in keys:
for k,v in a.items():
if a[i]==v:
ret_val.setdefault(i, []).append(k)
print (ret_val)
{1: [1, 2], 3: [3, 4]}
This was sort of stated in the comments by #Patrick Haugh:
d=your dictionary
s=set(d.values())
d2={i:[] for i in s}
for k in d:
d2[d[k]].append(k)
I have two dictionaries:
dict1 = {'a': 1,
'b': 2,
'c': 3,
'd': 4,
'x': 5}
and
dict2 = {'a': 'start',
'b': 'start',
'c': 'end',
'd': 'end'}
I am trying to create a new dictionary that maps the values start and end as keys to a dictionary that would contain the info of dict1, while keeping those that are not present in dict2 as keys, e.g.:
dict3 = {'start': {'a': 1, 'b': 2},
'end': {'c': 3, 'd': 4},
'x': {'x': 5}
}
Use dict.setdefault() to create the nested dictionaries in dict3 if not yet there, and dict.get() to determine the key in the top-level output dictionary:
dict3 = {}
for k, v in dict1.items():
nested = dict3.setdefault(dict2.get(k, k), {})
nested[k] = v
So dict2.get(k, k) will produce the value from dict2 for a given key from dict1, using the key itself as a default. So for the 'x' key, that'll produce 'x' as there is no mapping in dict2 for that key.
Demo:
>>> dict3 = {}
>>> for k, v in dict1.items():
... nested = dict3.setdefault(dict2.get(k, k), {})
... nested[k] = v
...
>>> dict3
{'start': {'a': 1, 'b': 2}, 'end': {'c': 3, 'd': 4}, 'x': {'x': 5}}
I actually figured it out while abstracting the example and typing up my question here (should have maybe done this earlier...). Anyways: Yay!
So here is my solution, in case it may help someone. If someone knows a swifter or more elegant way to do it, I would be glad to learn!
dict3 = dict()
for k, v in dict1.items():
# if the key of dict1 exists also in dict2
if k in dict2.keys():
# get its value (the keys-to-be for the new dict3)
new_key = dict2[k]
# if the new key is already in the new dict
if new_key in dict3.keys():
# appends new dict entry to dict3
dict3[new_key].update({k: v})
# otherwise create a new entry
else:
dict3[new_key] = {k: v}
# if there is no corresponding mapping present
else:
# treat the original key as the new key and add to dict3
no_map = k
dict3[no_map] = {k: v}