I've been trying to remove a specific item from multiple values in a dictionary in python and am not completely sure how to do this. For example, in the dictionary:
d = {('hello', 'hi', 'how are you'): 2, ('hi', 'hello', 'how are you'): 1}
How would I remove 'hi' so that all that remains is:
d = {('hello', 'how are you'): 2, ('hello', 'how are you'): 1}
You apparently want to change the key. So you simply need to store the corresponding value with the new key and remove the old one. However, in your case creating a new dict is easier since you want to modify every single item.
d2 = {}
for key, value in d.iteritems():
key = list(key)
if 'hi' in key:
key.remove('hi')
d2[tuple(key)] = value
d2 now contains {('hello', 'how are you'): 1}
As you can see it contains only one value unlike in your example because dicts cannot contain the same key twice.
You won't get the expected output here, as both keys are now same. So, only one of them can be found in the resulting dict.
In [142]: d = {('hello', 'hi', 'how are you'): 2, ('hi', 'hello', 'how are you'): 1}
In [143]: {tuple(y for y in x if y!='hi'):d[x] for x in d}
Out[143]: {('hello', 'how are you'): 1}
This should do it
answer = {}
for k,v in d.iteritems():
key = tuple(i for i in k if i!='hi')
answer[key] = v
d = answer
Not sure if this works for you, but this creates a new dictionary and will sum the values of any keys that end up colliding after removing 'hi' (assuming that is what you want to do - if not, disregard this answer :) ):
>>> from collections import defaultdict
>>> new_d = defaultdict(int)
>>> for k, v in d.iteritems():
... new_d[tuple(i for i in k if i != 'hi')] += v
...
>>> new_d
defaultdict(<type 'int'>, {('hello', 'how are you'): 3})
This does not correspond with your output, but as explained by everyone else, dictionaries can only have one key of a particular value, so this combines into one.
Related
I have this list made from a csv which is massive.
For every item in list, I have broken it into it's id and details. id is always between 0-3 characters max length and details is variable.
I created an empty dictionary, D...(rest of code below):
D={}
for v in list:
id = v[0:3]
details = v[3:]
if id not in D:
D[id] = {}
if details not in D[id]:
D[id][details] = 0
D[id][details] += 1
aside: Can you help me understand what the two if statements are doing? Very new to python and programming.
Anyway, it produces something like this:
{'KEY1_1': {'key2_1' : value2_1, 'key2_2' : value2_2, 'key2_3' : value2_3},
'KEY1_2': {'key2_1' : value2_1, 'key2_2' : value2_2, 'key2_3' : value2_3},
and many more KEY1's with variable numbers of key2's
Each 'KEY1' is unique but each 'key2' isn't necessarily. The value2_
s are all different.
Ok so, right now I found a way to sort by the first KEY
for k, v in sorted(D.items()):
print k, ':', v
I have done enough research to know that dictionaries can't really be sorted but I don't care about sorting, I care about ordering or more specifically frequencies of occurrence. In my code value2_x is the number of times its corresponding key2_x occurs for that particular KEY1_x. I am starting to think I should have used better variable names.
Question: How do I order the top-level/overall dictionary by the number in value2_x which is in the nested dictionary? I want to do some statistics to those numbers like...
How many times does the most frequent KEY1_x:key2_x pair show up?
What are the 10, 20, 30 most frequent KEY1_x:key2_x pairs?
Can I only do that by each KEY1 or can I do it overall? Bonus: If I could order it that way for presentation/sharing that would be very helpful because it is such a large data set. So much thanks in advance and I hope I've made my question and intent clear.
You could use Counter to order the key pairs based on their frequency. It also provides an easy way to get x most frequent items:
from collections import Counter
d = {
'KEY1': {
'key2_1': 5,
'key2_2': 1,
'key2_3': 3
},
'KEY2': {
'key2_1': 2,
'key2_2': 3,
'key2_3': 4
}
}
c = Counter()
for k, v in d.iteritems():
c.update({(k, k1): v1 for k1, v1 in v.iteritems()})
print c.most_common(3)
Output:
[(('KEY1', 'key2_1'), 5), (('KEY2', 'key2_3'), 4), (('KEY2', 'key2_2'), 3)]
If you only care about the most common key pairs and have no other reason to build nested dictionary you could just use the following code:
from collections import Counter
l = ['foobar', 'foofoo', 'foobar', 'barfoo']
D = Counter((v[:3], v[3:]) for v in l)
print D.most_common() # [(('foo', 'bar'), 2), (('foo', 'foo'), 1), (('bar', 'foo'), 1)]
Short explanation: ((v[:3], v[3:]) for v in l) is a generator expression that will generate tuples where first item is the same as top level key in your original dict and second item is the same as key in nested dict.
>>> x = list((v[:3], v[3:]) for v in l)
>>> x
[('foo', 'bar'), ('foo', 'foo'), ('foo', 'bar'), ('bar', 'foo')]
Counter is a subclass of dict. It accepts an iterable as an argument and each unique element in iterable will be used as key and value is the count of element in the iterable.
>>> c = Counter(x)
>>> c
Counter({('foo', 'bar'): 2, ('foo', 'foo'): 1, ('bar', 'foo'): 1})
Since generator expression is an iterable there's no need to convert it to list in between so construction can simply be done with Counter((v[:3], v[3:]) for v in l).
The if statements you asked about are checking if the key exists in dict:
>>> d = {1: 'foo'}
>>> 1 in d
True
>>> 2 in d
False
So the following code will check if key with value of id exists in dict D and if it doesn't it will assign empty dict there.
if id not in D:
D[id] = {}
The second if does exactly the same for nested dictionaries.
I'm working on a small framework and I've found a place where it would be beneficial to save a dictionary key as variable.
The problem I have is that the dictionary may have any number of layers, so it's not just a case of storing the final key. For example in the below I am accessing ['dig']['result'], but that could equally be ['output'] or ['some']['thing']['strange']
if result:
if self.cli_args.json:
pprint(result)
else:
print result['dig']['result']
I could save the key as a string and use eval() in something such as:
key="['test']"
test_dict = { "test" : "This works" }
eval("test_dict" + key)
>>> 'This works'
But eval is really dirty right? :-)
Is there a nice / pythonic way to do this?
To handle an arbitrary depth of key nesting, you can iterate over a sequence (e.g. tuple) of the keys:
>>> d = {'a': {'b': {'c': 'd'}}}
>>> d['a']['b']['c']
'd'
>>> keys = ('a', 'b', 'c') # or just 'abc' for this trivial example
>>> content = d
>>> for k in keys:
content = content[k]
>>> content
'd'
>>> def access(o,path):
... for k in path.split('/'):
... o = o[k]
... return o
...
>>> access({'a': {'b': {'c': 'd'}}},'a/b/c')
'd'
go through a dictionary picking keys from it in a loop?
For example lets say I have the following dictionary: {'hello':'world', 'hi':'there'}. Is there a way to for loop through the dictionary and print hello, hi?
on a similar note is there a way to say myDictionary.key[1] and that will return hi?
You can iterate over the keys of a dict with a for loop:
>>> for key in yourdict:
>>> print(key)
hi
hello
If you want them as a comma separated string you can use ', '.join.
>>> print(', '.join(yourdict))
hi, hello
on a similar note is there a way to say myDictionary.key1 and that will return hi
No. The keys in a dictionary are not in any particular order. The order that you see when you iterate over them may not be the same as the order you inserted them into the dictionary, and also the order could in theory change when you add or remove items.
if you need an ordered collection you might want to consider using another type such as a list, or an OrderedDict
You can use the .keys() method:
for key in myDictionary.keys():
print(key)
You can also use .items() to iterate through both at the same time:
for key, value in myDictionary.items():
print(key, value)
Using the dictionary name as a sequence produces all the keys:
>>> d={'hello':'world', 'hi':'there'}
>>> list(d)
['hi', 'hello']
so list({'hello':'world', 'hi':'there'})[1] produces element 1 of the list of keys.
This is of limited use, however, because dictionaries are unordered. And their order may be different than the order of insertion:
>>> d={'a': 'ahh', 'b': 'baa', 'c': 'coconut'}
>>> d
{'a': 'ahh', 'c': 'coconut', 'b': 'baa'}
You can do sorted(list({'hello':'world', 'hi':'there'}))[1] for the 1 element of a sorted list of the keys of your dict. That produces 'hi' in this case. Not the most readable or efficient though...
You should look at OrderedDict if you want a sorted order.
Or just sort into a list:
>>> d={'a': 'ahh', 'b': 'baa', 'c': 'coconut'}
>>> l=[(k,v) for k, v in d.items()]
>>> l.sort()
>>> l[1]
('b', 'baa')
>>> l[1][0]
'b'
You can reverse (k,v) to (v,k) if you want to sort by value instead of by key.
dict.iterkeys in Python 2, dict.keys in Python 3.
d = { 'hello': 'world', 'hi': 'there' }
for key in d.iterkeys():
print key
Sounds like a list of keys would meet your needs:
>>> d = { 'hello': 'world', 'hi': 'there' }
>>> keys = list(d)
>>> keys
['hi', 'hello']
>>> from random import choice
>>> choice(keys)
'hi'
What is the best way to remove an item from a dictionary by value, i.e. when the item's key is unknown? Here's a simple approach:
for key, item in some_dict.items():
if item is item_to_remove:
del some_dict[key]
Are there better ways? Is there anything wrong with mutating (deleting items) from the dictionary while iterating it?
The dict.pop(key[, default]) method allows you to remove items when you know the key. It returns the value at the key if it removes the item otherwise it returns what is passed as default. See the docs.'
Example:
>>> dic = {'a':1, 'b':2}
>>> dic
{'a': 1, 'b': 2}
>>> dic.pop('c', 0)
0
>>> dic.pop('a', 0)
1
>>> dic
{'b': 2}
Be aware that you're currently testing for object identity (is only returns True if both operands are represented by the same object in memory - this is not always the case with two object that compare equal with ==). If you are doing this on purpose, then you could rewrite your code as
some_dict = {key: value for key, value in some_dict.items()
if value is not value_to_remove}
But this may not do what you want:
>>> some_dict = {1: "Hello", 2: "Goodbye", 3: "You say yes", 4: "I say no"}
>>> value_to_remove = "You say yes"
>>> some_dict = {key: value for key, value in some_dict.items() if value is not value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 3: 'You say yes', 4: 'I say no'}
>>> some_dict = {key: value for key, value in some_dict.items() if value != value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 4: 'I say no'}
So you probably want != instead of is not.
a = {'name': 'your_name','class': 4}
if 'name' in a: del a['name']
A simple comparison between del and pop():
import timeit
code = """
results = {'A': 1, 'B': 2, 'C': 3}
del results['A']
del results['B']
"""
print timeit.timeit(code, number=100000)
code = """
results = {'A': 1, 'B': 2, 'C': 3}
results.pop('A')
results.pop('B')
"""
print timeit.timeit(code, number=100000)
result:
0.0329667857143
0.0451040902256
So, del is faster than pop().
I'd build a list of keys that need removing, then remove them. It's simple, efficient and avoids any problem about simultaneously iterating over and mutating the dict.
keys_to_remove = [key for key, value in some_dict.iteritems()
if value == value_to_remove]
for key in keys_to_remove:
del some_dict[key]
items() returns a list, and it is that list you are iterating, so mutating the dict in the loop doesn't matter here. If you were using iteritems() instead, mutating the dict in the loop would be problematic, and likewise for viewitems() in Python 2.7.
I can't think of a better way to remove items from a dict by value.
c is the new dictionary, and a is your original dictionary, {'z','w'}
are the keys you want to remove from a
c = {key:a[key] for key in a.keys() - {'z', 'w'}}
Also check: https://www.safaribooksonline.com/library/view/python-cookbook-3rd/9781449357337/ch01.html
y={'username':'admin','machine':['a','b','c']}
if 'c' in y['machine'] : del y['machine'][y['machine'].index('c')]
There is nothing wrong with deleting items from the dictionary while iterating, as you've proposed. Be careful about multiple threads using the same dictionary at the same time, which may result in a KeyError or other problems.
Of course, see the docs at http://docs.python.org/library/stdtypes.html#typesmapping
This is how I would do it.
for key in some_dict.keys():
if some_dict[key] == item_to_remove:
some_dict.pop(key)
break
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.