I'm kind of confused on d.items() and d.keys(). My textbook said that they return view objects that are tuples but they can be changed? For instance, my code is this
d = {"Bob":27, "Frank":75}
for key, value in d.items():
if d[key] == 27:
d[key] = 20
print(d)
It prints out 20 instead of 27.
What your textbook means is that if the keys of the dictionary change, then so will the view.
d = {1: 1}
keys = d.keys() # dict_keys([1])
d[2] = 2
keys # dict_keys([1, 2])
The same happens for items.
d = {1: 1}
items = d.items() # dict_items([(1, 1)])
d[2] = 2
keys # dict_keys([(1, 1), (2, 2)])
Also, they are not tuples, they have their own class.
isinstance(d.keys(), tuple) # False
type(d.keys()) # <class 'dict_keys'>
type(d.items()) # <class 'dict_items'>
a = {
'a': 'aa',
'b': 'bb',
'c': 'cc'
}
for k,v in a.items(): # does't change anything.
k = 'c' # k is the first item of the tuples in the dict_items object
for k in a.keys(): # doesn't change anything.
k = 'd' # k is the first item of the tuples in the dict_keys object
for k,v in a.items():
# you are using __setitem__ method of the dictionary with the first item of the tuple
# so you are not actually changing the tuple
# you are just using the tuple to index the dictionary
a[k] = v + '!!!' # you find the value of the given key, and added a string to it
print(a.items()) # will print a dict_items object containing key,value tuples of the dictionary
-~-~-~-~-~-
for a in a.items(): # does't change anything
print(isinstance(a,tuple))
The above code vill give you all True because every item in the dict_items object is indeed a tuple. a.items() doesn't return tuples yet returns an object which holds tuples.
Related
So I have a dictionary that contains nonunique key value pairs, I want to return a new dictionary where the key value pairs are reversed and all the non unique pair are removed from the new dictionary without modifying the original dictionary.
pls help :(
Input:
>>> invert({'one':1, 'two':2, 'uno':1, 'dos':2, 'three':3, 'un':1})
Expected result {3: 'three'}
This is my attempt at solving the problem:
inverted_dict = {}
for key,value in d.items(): #iterate throught a dict
nonu = value
if nonu in inverted_dict:
del inverted_dict[nonu]
else:
inverted_dict[value] = key
return inverted_dict
It returns: {3: 'three', 1: 'un'}
You need a way to keep track of keys you've seen other that the inverted dict because when you delete those keys from the dict, it is not longer effective. This has the effect of only saving keys with odd number of occurrences. Here's one way using a set to keep track of what you've seen:
def invert(d):
seen = set()
ret = {}
for k, v in d.items():
if v not in seen:
seen.add(v)
ret[v] = k
elif v in ret:
del ret[v]
return ret
invert({'one':1, 'two':2, 'uno':1, 'dos':2, 'three':3, 'un':1})
# {3: 'three'}
Here's how you might do it by counting using Python's built-in Collections.Counter:
from collections import Counter
def invert(d):
counts = Counter(d.values())
return {v:k for k, v in d.items() if counts[v] == 1}
invert({'one':1, 'two':2, 'uno':1, 'dos':2, 'three':3, 'un':1})
# {3: 'three'}
Continue from the previous question, write a function called get_sum(tuple_list) which accepts a list of tuple objects and returns a dictionary containing the sum of values of all the strings that appear in the list. For example, if we have the following data (a list of tuple objects):
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
then the dictionary should contain the following:
{'a': 10, 'b': 20}
My problem is how to distinguish a b value when sum them together
Test
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
sum_dict = get_sum(tuple_list)
for key in sorted(sum_dict.keys()):
print("{}: {}".format(key, sum_dict[key]))
Result
a: 10
b: 20
I would suggest to use defauldict. You can use a normal dict but it will take some more if statements.
from collections import defaultdict
d = defaultdict(int)
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
for a,b in tuple_list:
d[a] +=b
print (d)
#defaultdict(<class 'int'>, {'a': 10, 'b': 20})
If you want to use your original method, you can use tuple unpacking:
def get_sum(l):
new_dict = {}
for x, y in l:
if x not in new_dict:
new_dict[x] = y
else:
new_dict[x] +=y
return new_dict
print (get_sum(tuple_list))
#{'a': 10, 'b': 20}
A very simple solution using the standard dict 'get' method:
d={}
for c,v in tuple_list:
d[c]=d.get(c,0)+v
Try this out:
def get_sum(tuple_list):
new_dict = {}
for tuple in tuple_list:
if tuple[0] not in new_dict:
new_dict[tuple[0]] = tuple[1]
else:
new_dict[tuple[0]] += tuple[1]
return new_dict
tuple_list = [('a',5), ('a',5), ('b',6), ('b',4), ('b',3), ('b',7)]
sum_dict = get_sum(tuple_list)
for key in sorted(sum_dict.keys()):
print("{}: {}".format(key, sum_dict[key]))
If the entry is not in your list, then you make the dictionary key, value pair be the first and second indexes of the tuple. Otherwise, the key is already in the dictionary, so we simply add to its current value.
I have a dictionary that consists of numbers and their value
dict = {1:5, 2:5, 3:5}
I have an array with some numbers
arr = [1,2]
What I want to do is:
iterate through the dict and the array
where the dictionary value is equal to the number in the array, set the dictionary value to zero
any value in the dictionary for which there isn't a value in the array matching it, add 1
so in the above example, I should end up with
arr = [1,2]
dict = {1:0, 2:0, 3:6}
The bit I am getting stuck on is creating a variable from the array value and accessing that particular number in the dictionary - using dict[i] for example
arr = [1,2]
data = {1:0, 2:0, 3:6} # don't call it dict because it shadow build-in class
unique = set(arr) # speed up search in case if arr is big
# readable
for k, v in data.items():
if k in unique:
data[k] = 0
else:
data[k] += 1
# oneliner
data = {k: (0 if k in unique else v + 1) for v, k in data.items()}
Additional example:
for a, b, c in [(1,2,3), (4,5,6)]:
print('-',a,b,c)
# will print:
# - 1 2 3
# - 4 5 6
You just need a dict-comprehension that will re-built your dictionary with an if condition for the value part.
my_dict = {1:5, 2:5, 3:5}
arr = [1,2]
my_dict = {k: (0 if k in arr else v+1) for k, v in my_dict.items()}
print(my_dict) # {1: 0, 2: 0, 3: 6}
Note that I have re-named the dictionary from dict to my_dict. That is because by using dict you are overwriting the Python built-in called dict. And you do not want to do that.
Theirs always the dict(map()) approach, which rebuilds a new dictionary with new values to each of the keys:
>>> d = {1:5, 2:5, 3:5}
>>> arr = {1, 2}
>>> dict(map(lambda x: (x[0], 0) if x[0] in arr else (x[0], x[1]+1), d.items()))
{1: 0, 2: 0, 3: 6}
This works because wrapping dict() will automatically convert mapped 2-tuples to a dictionary.
Also you should not use dict as a variable name, since it shadows the builtin dict.
Just use .update method :
dict_1 = {1:5, 2:5, 3:5}
arr = [1,2]
for i in dict_1:
if i in arr:
dict_1.update({i:0})
else:
dict_1.update({i:dict_1.get(i)+1})
print(dict_1)
output:
{1: 0, 2: 0, 3: 6}
P.S : don't use dict as variable
I need to write a function which is doing following work
Find a string as value in a dictionary of dictionaries and return its key
(1st key if found in main dictionary, 2nd key if found in sub dictionary).
Source Code
Here is the function which I try to implement, but it works incorrect as I can't find any answer of how to convert list into dictionary as in this case the following error occurs
for v, k in l:
ValueError: need more than 1 value to unpack
def GetKeyFromDictByValue(self, dictionary, value_to_find):
""""""
key_list = [k for (k, v) in dictionary.items() if v == value_to_find]
if key_list.__len__() is not 0:
return key_list[0]
else:
l = [s for s in dictionary.values() if ":" in str(s)]
d = defaultdict(list)
for v, k in l:
d[k].append(v)
print d
dict = {'a': {'a1': 'a2'}, "aa": "aa1", 'aaa': {'aaa1': 'aaa2'}}
print GetKeyFromDictByValue(dict, "a2")
I must do this on Python 2.5
You created a list of only the dictionary values, but then try to loop over it as if it already contains both keys and values of those dictionaries. Perhaps you wanted to loop over each matched dictionary?
l = [v for v in dictionary.values() if ":" in str(v)]
d = defaultdict(list)
for subdict in l:
for k, v in subdict.items():
I'd instead flatten the structure:
def flatten(dictionary):
for key, value in dictionary.iteritems():
if isinstance(value, dict):
# recurse
for res in flatten(value):
yield res
else:
yield key, value
then just search:
def GetKeyFromDictByValue(self, dictionary, value_to_find):
for key, value in flatten(dictionary):
if value == value_to_find:
return key
Demo:
>>> sample = {'a': {'a1': 'a2'}, "aa": "aa1", 'aaa': {'aaa1': 'aaa2'}}
>>> GetKeyFromDictByValue(None, sample, "a2")
'a1'
This question already has answers here:
Reverse / invert a dictionary mapping
(32 answers)
Closed 10 months ago.
I receive a dictionary as input, and would like to to return a dictionary whose keys will be the input's values and whose value will be the corresponding input keys. Values are unique.
For example, say my input is:
a = dict()
a['one']=1
a['two']=2
I would like my output to be:
{1: 'one', 2: 'two'}
To clarify I would like my result to be the equivalent of the following:
res = dict()
res[1] = 'one'
res[2] = 'two'
Any neat Pythonic way to achieve this?
Python 2:
res = dict((v,k) for k,v in a.iteritems())
Python 3 (thanks to #erik):
res = dict((v,k) for k,v in a.items())
new_dict = dict(zip(my_dict.values(), my_dict.keys()))
From Python 2.7 on, including 3.0+, there's an arguably shorter, more readable version:
>>> my_dict = {'x':1, 'y':2, 'z':3}
>>> {v: k for k, v in my_dict.items()}
{1: 'x', 2: 'y', 3: 'z'}
You can make use of dict comprehensions:
Python 3
res = {v: k for k, v in a.items()}
Python 2
res = {v: k for k, v in a.iteritems()}
Edited: For Python 3, use a.items() instead of a.iteritems(). Discussions about the differences between them can be found in iteritems in Python on SO.
In [1]: my_dict = {'x':1, 'y':2, 'z':3}
Python 3
In [2]: dict((value, key) for key, value in my_dict.items())
Out[2]: {1: 'x', 2: 'y', 3: 'z'}
Python 2
In [2]: dict((value, key) for key, value in my_dict.iteritems())
Out[2]: {1: 'x', 2: 'y', 3: 'z'}
The current leading answer assumes values are unique which is not always the case. What if values are not unique? You will loose information!
For example:
d = {'a':3, 'b': 2, 'c': 2}
{v:k for k,v in d.iteritems()}
returns {2: 'b', 3: 'a'}.
The information about 'c' was completely ignored.
Ideally it should had be something like {2: ['b','c'], 3: ['a']}. This is what the bottom implementation does.
Python 2.x
def reverse_non_unique_mapping(d):
dinv = {}
for k, v in d.iteritems():
if v in dinv:
dinv[v].append(k)
else:
dinv[v] = [k]
return dinv
Python 3.x
def reverse_non_unique_mapping(d):
dinv = {}
for k, v in d.items():
if v in dinv:
dinv[v].append(k)
else:
dinv[v] = [k]
return dinv
You could try:
Python 3
d={'one':1,'two':2}
d2=dict((value,key) for key,value in d.items())
d2
{'two': 2, 'one': 1}
Python 2
d={'one':1,'two':2}
d2=dict((value,key) for key,value in d.iteritems())
d2
{'two': 2, 'one': 1}
Beware that you cannot 'reverse' a dictionary if
More than one key shares the same value. For example {'one':1,'two':1}. The new dictionary can only have one item with key 1.
One or more of the values is unhashable. For example {'one':[1]}. [1] is a valid value but not a valid key.
See this thread on the python mailing list for a discussion on the subject.
res = dict(zip(a.values(), a.keys()))
new_dict = dict( (my_dict[k], k) for k in my_dict)
or even better, but only works in Python 3:
new_dict = { my_dict[k]: k for k in my_dict}
Another way to expand on Ilya Prokin's response is to actually use the reversed function.
dict(map(reversed, my_dict.items()))
In essence, your dictionary is iterated through (using .items()) where each item is a key/value pair, and those items are swapped with the reversed function. When this is passed to the dict constructor, it turns them into value/key pairs which is what you want.
Suggestion for an improvement for Javier answer :
dict(zip(d.values(),d))
Instead of d.keys() you can write just d, because if you go through dictionary with an iterator, it will return the keys of the relevant dictionary.
Ex. for this behavior :
d = {'a':1,'b':2}
for k in d:
k
'a'
'b'
Can be done easily with dictionary comprehension:
{d[i]:i for i in d}
dict(map(lambda x: x[::-1], YourDict.items()))
.items() returns a list of tuples of (key, value). map() goes through elements of the list and applies lambda x:[::-1] to each its element (tuple) to reverse it, so each tuple becomes (value, key) in the new list spitted out of map. Finally, dict() makes a dict from the new list.
Hanan's answer is the correct one as it covers more general case (the other answers are kind of misleading for someone unaware of the duplicate situation). An improvement to Hanan's answer is using setdefault:
mydict = {1:a, 2:a, 3:b}
result = {}
for i in mydict:
result.setdefault(mydict[i],[]).append(i)
print(result)
>>> result = {a:[1,2], b:[3]}
Using loop:-
newdict = {} #Will contain reversed key:value pairs.
for key, value in zip(my_dict.keys(), my_dict.values()):
# Operations on key/value can also be performed.
newdict[value] = key
If you're using Python3, it's slightly different:
res = dict((v,k) for k,v in a.items())
Adding an in-place solution:
>>> d = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> for k in list(d.keys()):
... d[d.pop(k)] = k
...
>>> d
{'two': 2, 'one': 1, 'four': 4, 'three': 3}
In Python3, it is critical that you use list(d.keys()) because dict.keys returns a view of the keys. If you are using Python2, d.keys() is enough.
I find this version the most comprehensive one:
a = {1: 'one', 2: 'two'}
swapped_a = {value : key for key, value in a.items()}
print(swapped_a)
output :
{'one': 1, 'two': 2}
An alternative that is not quite as readable (in my opinion) as some of the other answers:
new_dict = dict(zip(*list(zip(*old_dict.items()))[::-1]))
where list(zip(*old_dict.items()))[::-1] gives a list of 2 tuples, old_dict's values and keys, respectively.