Change key names and add values of same keys - python

Let's suppose that I have a dictionary like that:
input_dict = {'3': 2, '5': 4, '36': 7,'62':6}
and I want to have that as an output:
input_dict = {'3': 9, '5': 4, '6':6}
Basically, I want to do the following things:
Keep only the first character of the keys
If after that some keys are the same then add their values
What is the most efficient way to do this?

You can use a defaultdict and slice the key strings keeping only the first character:
from collections import defaultdict
d = defaultdict(int)
for k,v in input_dict.items():
d[k[0]] += v
print(d)
# defaultdict(int, {'3': 9, '5': 4, '6': 6})

Use this:
new_dict = {}
for key, val in input_dict.items():
if key[0] not in new_dict:
new_dict[key[0]] = val
else:
new_dict[key[0]] += val
Output
{'3': 9, '5': 4, '6': 6}

You could use the get method from a dictionary:
input_dict = {'3': 2, '5': 4, '36': 7, '62': 6}
result = {}
for k, v in input_dict.items():
key = k[0]
result[key] = v + result.get(key, 0)
print(result)
Output
{'3': 9, '5': 4, '6': 6}

Related

How to make all keys except first key lowercase in dictionary

Here is a dictionary
dict1 = {'math': {'JOHN': 7,
'LISA': 4,
'KARYN': 3},
'eng': {'LISA': 5,
'TOBY':4,
'KARYN':11,
'RYAN':3},
'phy': {'KARYN': 7,
'JOHN': 7,
'STEVE':9,
'JOE':9}}
I would like to make the all letters in the keys except the 1st lower case.
This is what i've attempted
for i in dict1:
dict1 = dict(k.lower(), v) for k =! k[0], v in dict1[i].items())
dict1
It's failing because i'm not exactly sure how to apply the condition so that only the 1st letter remains capital.
If I understand correctly:
>>> {k: {kk.capitalize(): vv for kk, vv in v.items()} for k, v in dict1.items()}
{'math': {'John': 7, 'Lisa': 4, 'Karyn': 3},
'eng': {'Lisa': 5, 'Toby': 4, 'Karyn': 11, 'Ryan': 3},
'phy': {'Karyn': 7, 'John': 7, 'Steve': 9, 'Joe': 9}}
You can just create a new dictionary using the new keys and delete the old one.
from collections import defaultdict
# this creates a dictionary of dictionaries
dict2 = defaultdict(dict)
for key in dict1.keys():
for name in dict1[key]:
# get only the first letter in caps and the rest in lower
newname = name[0] + name.lower()[1:]
# create a new entry in the new dictionray using the old one
dict2[key][newname] = dict1[key][name]
The output is:
defaultdict(dict,
{'eng': {'Karyn': 11, 'Lisa': 5, 'Ryan': 3, 'Toby': 4},
'math': {'John': 7, 'Karyn': 3, 'Lisa': 4},
'phy': {'Joe': 9, 'John': 7, 'Karyn': 7, 'Steve': 9}})
which can be assessed just like a regular dictionary.
In python there is a function called capitalize(). Maybe it could help?
your_string = "ABRAKADABRA!"
print(your_string.capitalize())
returns
Abrakadabra!
https://www.geeksforgeeks.org/string-capitalize-python/

3 level nested dictionary comprehension in Python

I have a Python dictionary as follows:
d = {'1': {'1': 3, '2': 1, '3': 1, '4': 4, '5': 2, '6': 3},
'2': {'1': 3, '2': 3, '3': 1, '4': 2},
'3': {'1': 1, '2': 1, '3': 3, '4': 2, '5': 1, '6': 1, '7': 1},
'4': {'1': 1, '2': 1, '3': 3, '4': 2, '5': 1, '6': 1, '7': 1}}
I have this operation on the dictionary:
D = {}
for ko, vo in d.items():
for ki, vi in vo.items():
for i in range(vi):
D[f'{ko}_{ki}_{i}'] = someFunc(ko, ki, i)
I want to translate it into a one liner with dictionary comprehension as follows:
D = {f'{ko}_{ki}_{i}': someFunc(ko, ki, i) for i in range(vi) for ki, vi in vo.items() for ko, vo in d.items()}
But I get an error
NameError: name 'vi' is not defined
Can someone help me with the correct syntax for achieving this?
The order of the loops has to be reversed.
This is what you're looking for:
D = {f'{ko}_{ki}_{i}': someFunc(ko, ki, i) for ko, vo in d.items() for ki, vi in vo.items() for i in range(vi) }
The for clauses in the list comprehension should appear in the same order as in the equivalent for-loop code. The only thing that "moves" is that the innermost assignment is replaced by an expression at the beginning.
Please see https://treyhunner.com/2015/12/python-list-comprehensions-now-in-color/ for details.

How to make all the dictionary values unique in python?

I want a solution to make all the keys of a dictionary have a unique value, and to do that delete the values as minimum as possible to have each value unique. For example:
my_dict = {'c': 3, 'e': 3, 'a': 2, 'f': 2, 'd': 2}
for the above dictionary I need to sub 2 from 'f' and 3 of times from 'e' and 1 time from 'd'. and result would be 6 which means {'c':3, 'a':2, 'd':1}. Removing keys is not a problem.
note we could remove 'c' rather than 'e' or 'a' rather than f'' it's not important which key should be decreed or be removed , what matters is having unique values
This is what I have tried:
for k, v in my_dict.items():
c = 0
while len(my_dict.values()) > len(set(my_dict.values())):
my_dict[k] = my_dict[k] -1
c += 1
It is not the result you were expecting, but it meets the requirements.
my_dict = {'c': 3, 'e': 3, 'a': 2, 'f': 2, 'd': 2}
to_remove = []
result = {}
for key, value in my_dict.items():
while value > 0:
if value not in to_remove:
to_remove.append(value)
result[key] = value
break
else:
value -= 1
result
Simple approach:
my_dict = {'c': 3, 'e': 3, 'a': 2, 'f': 2, 'd': 2}
rd = {v: k for k, v in my_dict.items()}
my_dict = {v: k for k, v in rd.items()}
print(my_dict)

How to check if at least one key in dictionary exists as a value in another dictionary in Python?

I am creating a function that accepts a dictionary1 and checks if any of the keys exists as a value dictionary2.
I have tried using the dictionary2.isdisjoint(dictionary1) but this is effective for only checking keys-keys.
How can I check key to value in Python?
Not sure if this is really a big enough task to put into a separate function, but anyway, here's an example using the any() keyword:
if any(k in d2.values() for k in d1.keys()):
# do stuff
If the below statement returns True (it will return common values) then:
set(dictionary1.keys()) & set(dictionary2.values())
Explanation:
dictionary1.keys() will give the list of keys in dictionary1
dictionary2.values() will give the list of values in dictionary2
Convert these two to set and if they have common values, you will end
up with the common values between the two.
dictionary1 = {1:2, 2:3, 3:4}
dictionary2 = {2:1, 2:3, 3:4}
print set(dictionary1.keys()) & set(dictionary2.values())
Output:
set([3])
This isn't an operation that is built-in. You would need to write logic to do it yourself. You seem to be using python 3, so something like the below might work
>>> x = dict.fromkeys([0, 5, 10])
>>> y = {x: x for x in range(5)}
>>> print(x.keys().isdisjoint(y.values()))
False
>>> x.pop(0)
>>> print(x.keys().isdisjoint(y.values()))
True
d = {'1': 'one', '3': 'three', '2': 'two', '5': 'five', '4': 'four'}
d2 = {'5': 'five', '6': 'six', '7': 'eight', 'three': '3', '9': 'nine'}
for key in d:
if key in d2.itervalues():
print "found"
Your solution is almost right. You have to add not to proof the opposite (not disjoint == have common elements) and use the method values() to get values from the dictionary. In your case you check only keys of two dictionaries.
d1 = {i: i for i in range(5)}
d2 = {i: j for i, j in zip(range(5), range(5,10))}
d3 = {i: j for i, j in zip(range(5,10), range(5))}
print('d1: ', d1)
print('d2: ', d2)
print('Keys of d1 in values of d2: ', not set(d1).isdisjoint(d2.values()))
print('Keys of d1 in keys of d2: ', not set(d1).isdisjoint(d2))
print()
print('d2: ', d2)
print('d3: ', d3)
print('Keys of d2 in values of d3: ', not set(d2).isdisjoint(d3.values()))
print('Keys of d2 in keys of d3: ', not set(d2).isdisjoint(d3))
Output:
# d1: {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
# d2: {0: 5, 1: 6, 2: 7, 3: 8, 4: 9}
# Keys of d1 in values of d2: False
# Keys of d1 in keys of d2: True
#
# d2: {0: 5, 1: 6, 2: 7, 3: 8, 4: 9}
# d3: {5: 0, 6: 1, 7: 2, 8: 3, 9: 4}
# Keys of d2 in values of d3: True
# Keys of d2 in keys of d3: False

Find Maximum Value in Nested Dictionary and return Key

So I have this block of code
dictionary = {
'key1': {'a': 1, 'b': 2, 'c': 10},
'key2': {'d': 1, 'e': 1, 'c': 11},
'key3': {'d': 2, 'b': 1, 'g': 12}}
and
list1 = (a,b,c)
What I want to do is run a loop that finds the maximums of all the items in the list and returns the key. So for example, the maximum of 'c' would return 'key2', the maximum of 'b' would return 'key1', etc.
So far I have
for value in list1:
m = max(dictionary, key=lambda v: dictionary[v][value])
print(m + "\n")
But this only works if the same subkey exists in all keys in the dictionary. Any ideas on what to do?
Use float('-inf') when the key is missing:
m = max(dictionary, key=lambda v: dictionary[v].get(value, float('-inf')))
Negative infinity is guaranteed to be smaller than any existing value in the dictionaries, ensuring that nested dictionaries with the specific key missing are ignored.
Demo:
>>> dictionary = {
... 'key1': {'a': 1, 'b': 2, 'c': 10},
... 'key2': {'d': 1, 'e': 1, 'c': 11},
... 'key3': {'d': 2, 'b': 1, 'g': 12}}
>>> list1 = ('a', 'b', 'c')
>>> for value in list1:
... print(value, max(dictionary, key=lambda v: dictionary[v].get(value, float('-inf'))))
...
a key1
b key1
c key2
However, it'll be more efficient if you looped over all your dictionary values just once instead:
maximi = dict.fromkeys(list1, (None, float('-inf')))
for key, nested in dictionary.items():
for k in nested.keys() & maximi: # intersection of keys
if maximi[k][0] is None or dictionary[maximi[k][0]][k] < nested[k]:
maximi[k] = (key, nested[k])
for value in list1:
print(value, maximi[value][0])
That's presuming you are using Python 3; in Python 2, replace .items() with .iteritems() and .keys() with .viewkeys().
Demo:
>>> maximi = dict.fromkeys(list1, (None, float('-inf')))
>>> for key, nested in dictionary.items():
... for k in nested.keys() & maximi: # intersection of keys
... if maximi[k][0] is None or dictionary[maximi[k][0]][k] < nested[k]:
... maximi[k] = (key, nested[k])
...
>>> maximi
{'a': ('key1', 1), 'b': ('key1', 2), 'c': ('key2', 11)}
>>> for value in list1:
... print(value, maximi[value][0])
...
a key1
b key1
c key2

Categories