Check if repeating Key or Value exists in Python Dictionary - python

The following is my dictionary and I need to check if I have repeated key or Value
dict = {' 1': 'a', '2': 'b', '3': 'b', '4': 'c', '5': 'd', '5': 'e'}
This should return false or some kind of indicator which helps me print out that key or value might be repeated. It would be much appreciated if I am able to identify if a key is repeated or a Value (but not required).

Dictionaries can't have duplicate keys, so in case of repeated keys it only keeps the last value, so check values (one-liner is your friend):
print(('There are duplicates' if len(set(dict.values()))!=len(values) else 'No duplicates'))

Well in a dictionary keys can't repeat so we only have to deal with values.
dict = {...}
# get the values
values = list(dict.values())
And then you can use a set() to check for duplicates:
if len(values) == len(set(values)): print("no duplicates")
else: print("duplicates)

It's not possible to check if a key repeats in a dictionary, because dictionaries in Python only support unique keys. If you enter the dictionary as is, only the last value will be associated with the redundant key:
In [4]: dict = {' 1': 'a', '2': 'b', '3': 'b', '4': 'c', '5': 'd', '5': 'e'}
In [5]: dict
Out[5]: {' 1': 'a', '2': 'b', '3': 'b', '4': 'c', '5': 'e'}

A one-liner to find repeating values
In [138]: {v: [k for k in d if d[k] == v] for v in set(d.values())}
Out[138]: {'a': [' 1'], 'b': ['2', '3'], 'c': ['4'], 'e': ['5']}
Check all the unique values of the dict with set(d.values()) and then creating a list of keys that correspond to those values.
Note: repeating keys will just be overwritten
In [139]: {'a': 1, 'a': 2}
Out[139]: {'a': 2}

What about
has_dupes = len(d) != len(set(d.values()))
I'm on my phone so I cant test it. But j think it will work.

Well, although key value should be unique according to the documentation, there is still condition where repeated key could appear.
For example,
>>> import json
>>> a = {1:10, "1":20}
>>> b = json.dumps(a)
>>> b
'{"1": 20, "1": 10}'
>>> c = json.loads(b)
>>> c
{u'1': 10}
>>>
But in general, when python finds out there's conflict, it takes the latest value assigned to that key.
For your question, you should use comparison such as
len(dict) == len(set(dict.values()))
because set in python contains an unordered collection of unique and immutable objects, it could automatically get all unique values even when you have duplicate values in dict.values()

Related

How to merge keys of dictionary which have the same value?

I need to combine two dictionaries by their value, resulting in a new key which is the list of keys with the shared value. All I can find online is how to add two values with the same key or how to simply combine two dictionaries, so perhaps I am just searching in the wrong places.
To give an idea:
dic1 = {'A': 'B', 'C': 'D'}
dic2 = {'D': 'B', 'E': 'F'}
Should result in:
dic3 = {['A', 'D']: 'B', 'C': 'D', 'E': 'F'}
I am not sure why you would need such a data structure, you can probably find a better solution to your problem. However, just for the sake of answering your question, here is a possible solution:
dic1 = {'A':'B', 'C':'D'}
dic2 = {'D':'B', 'E':'F'}
key_list = list(dic2.keys())
val_list = list(dic2.values())
r = {}
for k,v in dic1.items():
if v in val_list:
i = val_list.index(v) #get index at value
k2 = key_list[i] #use index to retrive the key at value
r[(k, k2)] = v #make the dict entry
else:
r[k] = v
val_list = list(r.values()) #get all the values already processed
for k,v in dic2.items():
if v not in val_list: #if missing value
r[k] = v #add new entry
print(r)
output:
{('A', 'D'): 'B', 'C': 'D', 'E': 'F'}
You can't assign a list as a key in a python dictionary since the key must be hashable and a list is not an ashable object, so I have used a tuple instead.
I would use a defaultdict of lists and build a reversed dict and in the end reverse it while converting the lists to tuples (because lists are not hashable and can't be used as dict keys):
from collections import defaultdict
dic1 = {'A':'B', 'C':'D'}
dic2 = {'D':'B', 'E':'F'}
temp = defaultdict(list)
for d in (dic1, dic2):
for key, value in d.items():
temp[value].append(key)
print(temp)
res = {}
for key, value in temp.items():
if len(value) == 1:
res[value[0]] = key
else:
res[tuple(value)] = key
print(res)
The printout from this (showing the middle step of temp) is:
defaultdict(<class 'list'>, {'B': ['A', 'D'], 'D': ['C'], 'F': ['E']})
{('A', 'D'): 'B', 'C': 'D', 'E': 'F'}
If you are willing to compromise from 1-element tuples as keys, the second part will become much simpler:
res = {tuple(value): key for key, value in temp.items()}

Add new key-value pair at the beginning of a dictionary

I have list of dictionaries. Now, in every dictionary, i want to add a key value pair(key : 'message1') at the beginning of the dict, but when i add it , its getting added to the end.
Following is my code
data=[{
'message2': 'asd',
'message3': 'fgw',
'message4': 'fgeq',
'message5': 'gqe',
'message6': 'afgq',
'message7': 'major',
'message8': 'color-regular'
}]
for i in data:
i['message1'] = '111'
Following is the output i am getting where message1 is appended in the end
[{'message2': 'asd',
'message3': 'fgw',
'message4': 'fgeq',
'message5': 'gqe',
'message6': 'afgq',
'message7': 'major',
'message8': 'color-regular',
'message1': '111'# i want this in the beginning}]
Please suggest a workaround
Simple way do to this can be create a dict first:
data = {'m1': 'A', 'm2': 'D'}
and then use update:
data.update({'m3': 'C', 'm4': 'B'})
Result will be {'m1': 'A', 'm2': 'D', 'm3': 'C', 'm4': 'B'}. The assumption is python version 3.7+ for an ordered dict. In the other way, you can use collections.OrderedDict.
On python3.7+ (cpython3.6+), dictionaries are ordered, so you can create a new dict with "message" as the first key:
for i, d in enumerate(data):
data[i] = {'message': '111', **d}
data
[{'message': '111',
'message2': 'asd',
'message3': 'fgw',
'message4': 'fgeq',
'message5': 'gqe',
'message6': 'afgq',
'message7': 'major',
'message8': 'color-regular'}]
You can do it like this:
dict1 = {
'1': 'a',
'2': 'b'
}
items = list(dict1.items())
items.insert(0, ('0', 'z'))
dict1 = dict(items)
print(dict1)
# {'0': 'z', '1': 'a', '2': 'b'}

switch key and values in a dict of lists

Hello Stackoverflow people,
I have a nested dictionary with lists as values and I want to create a dict where all the list entries get their corresponding key as value.
Example time!
# what I have
dict1 = {"A":[1,2,3], "B":[4,5,6], "C":[7,8,9]}
# what I want
dict2 = {1:"A", 2:"A", 3:"A", 4:"B", 5:"B", 6:"B", 7:"C", 8:"C", 9:"C"}
Any help will be much appreciated!
Try this
dict1 = {"A":[1,2,3], "B":[4,5,6], "C":[7,8,9]}
dict2= {}
for keys,values in dict1.items():
for i in values:
dict2[i]=keys
print(dict2)
Output
{1: 'A', 2: 'A', 3: 'A', 4: 'B', 5: 'B', 6: 'B', 7: 'C', 8: 'C', 9: 'C'}
Hope it helps
Use dictionary comprehension:
d = {'a': 'b', 'c': 'd', 'e': 'f'}
d2 = dict((v1, k) for k, v in d.items() for v1 in v) # Here is the one-liner
assuming your key: value dictionary contains list as a value and using dict comprehension.
Using a second loop to iterate over the list present in original dictionary.
{item: key for key, value in dict1.items() for item in value}

How to change a dictionary while iterating over its keys while iterating over a list

I have a list l.
I have a dictionary d.
I want to iterate over l. For any list-item, I want to iterate over the d.keys.
If some condition is met, I would like to 'update' my dictionary.
I have naively tried to nest two for-loops and put in an if-statement -- One cannot change the length of the object one is iterating over.
d = {'this': '1', 'is': '2', 'a': '3', 'list': '4'}
l = ['A', 'B', 'C', 'D', 'E']
for word in l:
for key in d.keys():
if len(key) < 2:#some condition
d.pop(key)
else:
print(word, key)
This is the output I get:
A this
A is
Traceback (most recent call last):
File "untitled3.py", line 6, in <module>
for key in d.keys():
RuntimeError: dictionary changed size during iteration
Instead of looping over d you could loop over a copy.
d = {'this': '1', 'is': '2', 'a': '3', 'list': '4'}
l = ['A', 'B', 'C', 'D', 'E']
for word in l:
for key in d.copy().keys(): # Notice the change
if len(key) < 2:#some condition
d.pop(key)
else:
print(word, key)
You should not change the size of a dictionary while iterating over a view of that dictionary. You can, instead, construct a new dictionary and then print whatever you like. For example:
d = {'this': '1', 'is': '2', 'a': '3', 'list': '4'}
L = ['A', 'B', 'C', 'D', 'E']
d_new = {k: v for k, v in d.items() if len(k) >= 2}
for word in L:
for key in d_new:
print(word, key)
As described in the docs:
The objects returned by dict.keys(), dict.values() and
dict.items() are view objects. They provide a dynamic view on the
dictionary’s entries, which means that when the dictionary changes,
the view reflects these changes....
Iterating views while adding or deleting entries in the dictionary may
raise a RuntimeError or fail to iterate over all entries.

Python miminum value in dictionary of lists

Sorry about the question repost...I should have just edited this question in the first place. Flagged the new one for the mods. Sorry for the trouble
Had to re-write the question due to changed requirements.
I have a dictionary such as the following:
d = {'a': [4, 2], 'b': [3, 4], 'c': [4, 3], 'd': [4, 3], 'e': [4], 'f': [4], 'g': [4]}
I want to get the keys that are associated with the smallest length in the dictionary d, as well as those that have the maximum value.
In this case, the keys with the smallest length (smallest length of lists in this dictionary) should return
'e, 'f', 'g'
And those with the greatest value(the sum of the integers in each list) should return
'b' 'c'
I have tried
min_value = min(dict.itervalues())
min_keys = [k for k in d if dict[k] == min_value]
But that does not give me the result I want.
Any ideas?
Thanks!
Your problem is that your lists contain strings ('2'), and not integers (2). Leave out the quotes, or use the following:
min_value = min(min(map(int, v) for v in dct.values()))
min_keys = [k for k,v in d.items() if min_value in map(int, v)]
Similarily, to calculate the keys with the max length:
max_length = max(map(len, dct.values()))
maxlen_keys = [k for k,v in d.items() if max_length == len(v)]
Also, it's a bad idea to use dict as a variable name, as doing so overshadows the built-in dict.
You can use min() with a key= argument, and specify a key function that compares the way you want.
d = {'a': ['1'], 'b': ['1', '2'], 'c': ['2'], 'd':['1']}
min_value = min(d.values())
min_list = [key for key, value in d.items() if value == min_value]
max_len = len(max(d.values(), key=len))
long_list = [key for key, value in d.items() if len(value) == max_len]
print(min_list)
print(long_list)
Notes:
0) Don't use dict as a variable name; that's the name of the class for dictionary, and if you use it as a variable name you "shadow" it. I just used d for the name here.
1) min_value was easy; no need to use a key= function.
2) max_len uses a key= function, len(), to find the longest value.
How about using sorting and lambdas?
#!/usr/bin/env python
d = {'a': ['1'], 'b': ['1', '2'], 'c': ['8', '1'], 'd':['1'], 'e':['1', '2', '3'], 'f': [4, 1]}
sorted_by_sum_d = sorted(d, key=lambda key: sum(list(int(item) for item in d[key])))
sorted_by_length_d = sorted(d, key=lambda key: len(d[key]))
print "Sorted by sum of the items in the list : %s" % sorted_by_sum_d
print "Sorted by length of the items in the list : %s" % sorted_by_length_d
This would output:
Sorted by sum of the items in the list : ['a', 'd', 'b', 'f', 'e', 'c']
Sorted by length of the items in the list : ['a', 'd', 'c', 'b', 'f', 'e']
Be aware I changed the initial 'd' dictionary (just to make sure it was working)
Then, if you want the item with the biggest sum, you get the last element of the sorted_by_sum_d list.
(I'm not too sure this is what you want, though)
Edit:
If you can ensure that the lists are always going to be lists of integers (or numeric types, for that matter, such as long, float...), there's not need to cast strings to integers. The calculation of the sorted_by_sum_d variable can be done simply using:
d = {'a': [1], 'b': [1, 2], 'c': [8, 1], 'd':[1], 'e':[1, 2, 3], 'f': [4, 1]}
sorted_by_sum_d = sorted(d, key=lambda key: sum(d[key]))
I've found such a simple solution:
min_len = len(min(d.values(), key=(lambda value: len(value)))) # 1
min_keys = [key for i, key in enumerate(d) if len(d[key]) == min_len] # ['e', 'f', 'g']

Categories

Resources