removing all the keys with the same value in dictionary - python

I want to get a new dictionary by removing all the keys with the same value (keys are differents, values are the same)
For example: Input:
dct = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
expected output:
{'key2': [1, 2, 6]}
key1 and key3 was deleted because they shared same values.
I have no idea about it?

You can do this by creating a dictionary based on the values. In this case the values are lists which are not hashable so convert to tuple. The values in the new dictionary are lists to which we append any matching key from the original dictionary. Finally, work through the new dictionary looking for any values where the list length is greater than 1 - i.e., is a duplicate. Then we can remove those keys from the original dictionary.
d = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
control = {}
for k, v in d.items():
control.setdefault(tuple(v), []).append(k)
for v in control.values():
if len(v) > 1:
for k in v:
del d[k]
print(d)
Output:
{'key2': [1, 2, 6]}

I created a list of counts which holds information about how many times an item is in the dictionary. Then I copy only items which are there once.
a = {"key1": [1,2,3], "key2": [1,2,6], "key3": [1,2,3]}
# find how many of each item are there
counts = list(map(lambda x: list(a.values()).count(x), a.values()))
result = {}
#copy only items which are in the list once
for i,item in enumerate(a):
if counts[i] == 1:
result[item] = a[item]
print(result)

As given by the OP, the simplest solution to the problem:
dct = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
print({k:v for k, v in dct.items() if list(dct.values()).count(v) == 1})
Output:
{'key2': [1, 2, 6]}

One loop solution:
dict_ = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
key_lookup = {}
result = {}
for key, value in dict_.items():
v = tuple(value)
if v not in key_lookup:
key_lookup[v] = key
result[key] = value
else:
if key_lookup[v] is not None:
del result[key_lookup[v]]
key_lookup[v] = None
print(result)
Output:
{'key2': [1, 2, 6]}

dct = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
temp = list(dct.values())
result = {}
for key, value in dct.items():
for t in temp:
if temp.count(t) > 1:
while temp.count(t) > 0:
temp.remove(t)
else:
if t == value:
result[key] = value
print(result)
Output:
{'key2': [1, 2, 6]}

Related

Creating nested dictionary from two lists one of which contains dictionaries

Very similar to this question but with an added caveat.
I have two lists identical in length. One contains my keys, and the other contains a list of dictionaries belonging to said keys. Example below (yes the Nones are intentional)
keys = ['key1', 'key2, 'key3']
vals = [[{'subkey1': 'val1', 'subkey2': 'val2'}], [{'subkey1: 'val2'},None],[{'subkey1':'val3'}, {'subkey3':'val1}, None, None]]
What I'd like to do is match each dictionary in each list to a key to create a nested dict.
So something like below:
final = {'key1':{'subkey1': 'val1', 'subkey2': 'val2'}, 'key2':{'subkey1': 'val2'}, 'key3':{'subkey1':'val3'}, {'subkey3':'val1'}}
I know we can use dictionary comprehension to do this. I created a dictionary of empty dicts.
s = {}
for i in keys:
for v in vals:
s[i] = {}
break
Then I wrote the following to iterate through the list of dicts I'd like to pair up accounting for the non dictionary values in my list.
x = 0
while x < len(keys):
for i in keys:
for element in vals[x]:
if isinstance(element, dict) == True:
s[str(i)].append(element)
else:
print('no')
x=x+1
However when I run this, I get AttributeError: 'NoneType' object has no attribute 'append'
How can I append to a dictionary using this for loop?
For the less readable dictionary comprehension solution
keys = ['key1', 'key2', 'key3']
vals = [
[{'subkey1': 'val1', 'subkey2': 'val2'}],
[{'subkey1': 'val2'}, None],
[{'subkey1': 'val3'}, {'subkey3':'val1'}, None, None]
]
s = {
k: {
sk: sv for d in (x for x in v if x is not None) for sk, sv in d.items()
} for k, v in zip(keys, vals)
}
Gives
{'key1': {'subkey1': 'val1', 'subkey2': 'val2'},
'key2': {'subkey1': 'val2'},
'key3': {'subkey1': 'val3', 'subkey3': 'val1'}}
This can be done fairly easily using a defaultdict:
from collections import defaultdict
keys = ['key1', 'key2', 'key3']
vals = [
[{'subkey1': 'val1', 'subkey2': 'val2'}],
[{'subkey1': 'val2'},None],
[{'subkey1':'val3'}, {'subkey3':'val1'}, None, None]
]
final = defaultdict(dict)
for idx, key in enumerate(keys):
for d in vals[idx]:
if d is not None:
final[key].update(d)
Output:
defaultdict(<class 'dict'>, {
'key1': {'subkey1': 'val1', 'subkey2': 'val2'},
'key2': {'subkey1': 'val2'},
'key3': {'subkey1': 'val3', 'subkey3': 'val1'}
})
can't use append on a dict
try this maybe?
keys = ['key1', 'key2', 'key3']
vals = [[{'subkey1': 'val1', 'subkey2': 'val2'}], [{'subkey1': 'val2'},None],[{'subkey1':'val3'}, {'subkey3':'val1'}, None, None]]
s = {}
for i in keys:
s[i] = {}
for i, key in enumerate(keys):
for element in vals[i]:
if isinstance(element, dict) == True:
s[str(key)].update(element)
print(s)
Output:
{'key1': {'subkey1': 'val1', 'subkey2': 'val2'}, 'key2': {'subkey1': 'val2'}, 'key3': {'subkey1': 'val3', 'subkey3': 'val1'}}

How to remove duplicate from list of values

I have list of dictionary
dictio =[{'key1':'value1'}, {'key1':'value2'}, {'key1':'value1'}, {'key2':'value4'}, {'key2':'value5'}]
from collections import defaultdict
result = defaultdict(list)
for subd in dictio:
for k, v in subd.items():
result[k].append(v)
result
My output
While appending 'value1' appending to 'key1' which is not required
defaultdict(list,
{'key1': ['value1', 'value2', 'value1'],
'key2': ['value4', 'value5']})
My Expected
`defaultdict(list,
{'key1': ['value1', 'value2'],
'key2': ['value4', 'value5']})`
You can turn your list of dict into a set and then in a list again, a set would remove all duplicates.
dictio = list(set([{'key1':'value1'}, {'key1':'value2'}, {'key1':'value1'}, {'key2':'value4'}, {'key2':'value5'}]))
You can achieve that very simply, just check if the element is already in:
dictio =[{'key1':'value1'}, {'key1':'value2'}, {'key1':'value1'}, {'key2':'value4'}, {'key2':'value5'}]
from collections import defaultdict
result = defaultdict(list)
for subd in dictio:
for k, v in subd.items():
if v not in result[k]:
result[k].append(v)
Instead of list use set
Ex:
dictio =[{'key1':'value1'}, {'key1':'value2'}, {'key1':'value1'}, {'key2':'value4'}, {'key2':'value5'}]
from collections import defaultdict
result = defaultdict(set)
for subd in dictio:
for k, v in subd.items():
result[k].add(v)
result
# --> defaultdict(<class 'set'>, {'key1': {'value2', 'value1'}, 'key2': {'value4', 'value5'}})
Try this example from https://www.w3schools.com/python/python_howto_remove_duplicates.asp
mylist = ["a", "b", "a", "c", "c"]
mylist = list(dict.fromkeys(mylist))
print(mylist)

Update dictionary key(s) by drop starts with value from key in Python

I have a dictionary dict:
dict = {'drop_key1': '10001', 'drop_key2':'10002'}
The key(s) in dict startswith drop_, i would like to update dict by dropping drop_ value from key(s):
dict = {'key1': '10001', 'key2':'10002'}
What is the best approach to do it?
something like
d1 = {'drop_key1': '10001', 'drop_key2':'10002'}
d2 = {k[5:]:v for k,v in d1.items()}
print(d2)
output
{'key1': '10001', 'key2': '10002'}
One approach is, for each key value in the dictionary, you can replace the part of the string with the new string value. For instance:
d = {k.replace('drop_', ''): v for k, v in d.items() if k.strip().startswith('drop_')}
or you can define a function, and get the index of the searched string ("drop_"). If the search string index is 0, then remove it. For instance:
def change_key(key, search):
start_idx = key.find(search)
if start_idx == 0:
key = key.replace(search, "")
return key
d = {change_key(k, search="drop_"): v for k, v in d.items()}
Result:
{'key1': '10001', 'key2': '10002'}
Note that if you use a method, then you can guarantee to remove the search string if it is at the beginning of the string. For instance:
d = {' drop_key1': '10001', 'drop_key2': '10002'}
d = {change_key(k, search="drop_"): v for k, v in d.items()}
Result:
{' drop_key1': '10001', 'key2': '10002'}

How do I update existing values and append new values to a dictionary?

I have N dataframes, from each of which I'm extracting df['col'].value_counts() and converting these to a dictionary so I have:
my_dict = {'key1' : val1, 'key2' : val2, ... , 'keyM' : valM}
How do I update my_dict so that:
If a random new dataframe D has the same key as a previous dataframe (e.g. 'key1'), then it adds the value to val1. In other words, if 'key1' had a value of 21 and the new dataframe has a value of 18 for the same key ('key1') , the dictionary key value should now be 'key1' : 39.
If however, the key does not exist, then it should create a new key with the relevant value.
Does that make sense? I feel like I'm overcomplicating this...
collections.Counter is built for this.
from collections import Counter
c1 = Counter(my_dict)
c2 = Counter(my_other_dict)
c_sum = c1 + c2
On the other hand, you should be able to do this within pandas too; value_counts() returns a Series which you should be able to add to other Series objects directly and have it behave how you expect.
Iterate over the key/values of new keys and update my_dict. You should also look into using defaultdict from the collections module
my_dict = {'key1': 21, 'key2': 10}
my_dict2 = {'key1': 18, 'key3': 5}
for k, v in my_dict2.items():
if k in my_dict:
my_dict[k] += v
else:
my_dict[k] = v
Using defaultdict
from collections import defaultdict
my_dict = defaultdict(int, {'key1': 21, 'key2': 10})
my_dict2 = {'key1': 18, 'key3': 5}
for k, v in my_dict2.items():
my_dict[k] += v
Here's another answer that uses collections as well:
from collections import defaultdict as ddict
some_list_of_dicts = [
{'val1': 5, 'val2': 3},
{'val1': 2, 'val2': 1, 'val3': 9},
]
my_dict = ddict(int)
for i in some_list_of_dicts:
for key, count in i.items():
my_dict[key] += count
print(dict(my_dict))
A defaultdict of int will be initialised to 0 when an unknown key is introduced.

Python Join 2 dictionaries into 3rd, 2D dictionary where key from dictionary 2 is list value in dictionary 1

I couldn't find this particular python dictionary question anywhere.
I have two dictionaries:
dict1 = {'key1':['val1','val2','val3']}
dict2 = {'val1':['a','b','c']}
I want a 3rd, 2D dictionary with:
dict3 = {'key1': {'val1':['a','b','c']} }
So, joining 2 dictionaries where the key of the second dictionary is a list value of the first dictionary.
I was trying some nested looping along the lines of:
for key1, val1 in dict1.items():
for key2, in val2 in dict2.items():
# do something here
I am not sure if that is the best way to do this.
This is best done by iterating over dict1 and looking for matching values in dict2:
result = {}
for key, value_list in dict1.items():
result[key] = subdict = {}
for value in value_list:
try:
subdict[value] = dict2[value]
except KeyError:
pass
Result:
{'key1': {'val1': ['a', 'b', 'c']}}
You can use a dictionary comprehension and then check if the final result contains only one dictionary. If the latter is true, then a dictionary of dictionaries will be the final result; else, a listing of dictionaries will be stored for the key:
dict1 = {'key1':['val1','val2','val3']}
dict2 = {'val1':['a','b','c']}
new_dict = {a:[{i:dict2[i]} for i in b if i in dict2] for a, b in dict1.items()}
last_result = {a:b if len(b) > 1 else b[0] for a, b in new_dict.items()}
Output:
{'key1': {'val1': ['a', 'b', 'c']}}
dict1 = {
'key1':['val1','val2','val3']
}
dict2 = {
'val1':['a','b','c']
}
dict3 = {
key : { val_key : dict2[val_key]
for val_key in val_list if (val_key in dict2.keys())
} for key, val_list in dict1.items()
}
You can try this solution .
dict1 = {'key1':['val1','val2','val3']}
dict2 = {'val1':['a','b','c']}
join_dict={}
for i,j in dict1.items():
for sub_l,sub_value in dict2.items():
if sub_l in j:
join_dict[i]={sub_l:sub_value}
print(join_dict)
output:
{'key1': {'val1': ['a', 'b', 'c']}}

Categories