This question already has answers here:
Can't modify list elements in a loop [duplicate]
(5 answers)
Closed 9 months ago.
I am trying to write a function replace(d, v, e) where d is a dict and v and e are ints. The function is supposed to replace all dictionary values of v to e.
This code works fine:
def replace(d, v, e):
for key, value in d.items():
if value == v:
d[key] = e
return d
print(replace({1:2, 3:4, 4:2}, 2, 7)) # output: {1: 7, 3: 4, 4: 7}
But when I alter the code to change the value using d.values(), it doesn't work:
def replace(d, v, e):
for i in d.values():
if i == v:
i = e
return d
print(replace({1:2, 3:4, 4:2}, 2, 7)) # output: {1: 2, 3: 4, 4: 2}
May I have any advice on how to modify the 2nd code to make it work like the 1st code?
Modifying the second code "to work" would require using items in place of values, so in short, you cannot modify the value without knowing the key. What your second code does is only to assign the value to i locally in the function without ever affecting the dictionary.
Another remark, your first version of the function modifies the dictionary in place and returns it, which is not a really good practice, you should do either the one or the other.
Finally, here is a version to return a new dictionary without changing the input, using a dictionary comprehension:
def replace(d, v, e):
return {k: e if val==v else val for k,val in d.items()}
replace({1: 2, 3: 4, 4: 2}, 2, 7)
# {1: 7, 3: 4, 4: 7}
Related
For example, I have a dictionary like such:
sampleDict = {0: 0, 1: 10, 2: 2, 3: 3, 4: 4}
I know that I can use the get() function to get the value of a particular key, but is there a way to do the opposite in a conditional manner?
For example, what if I wanted to get the key for maximum number in sampleDict. Is there a good function or set of functions I can use to quickly and efficiently get that value? I've tried a quick Google search, but I'm not coming up with what I want. In this example, I would want to receive the number 1 since the value for key 1 is the maximum value in the dictionary.
To get with max value you can use max() builtin function:
sampleDict = {0: 0, 1: 10, 2: 2, 3: 3, 4: 4}
max_key = max(sampleDict, key=sampleDict.get)
print(max_key)
Prints:
1
This return a array of keys that have the value you search.
keys = [k for k, v in sampleDict.items() if v == value]
print(keys)
You can use a loop to find the key which matches the max value:
sampleDict = {0: 0, 1: 10, 2: 2, 3: 3, 4: 4}
def foo(sampleDict):
m = max(sampleDict.values())
for k, v in sampleDict.items():
if v == m:
return k
print(foo(sampleDict))
Result: 1
This obviously does not account for any dupe max values. It just finds the first value that matches the max.
In terms of performance, this assumes the input size is not massive.
If we needed to make it more efficient, we could calculate the maximum as we iterate.
Suppose I have a function that returns a tuple:
def foo(x):
return (x, x*100)
I have a list of values that I'd like to apply the function on and then turn the results into a dictionary:
list_of_vals = [2, 4, 6]
result = {...magic comprehension...}
print(result)
# {2: 200, 4: 400, 6: 600}
I've come up with two ways to do this:
{ k: v for k, v in map(foo, list_of_vals)}
{ k: v for k, v in (foo(val) for val in list_of_vals} # equivalently
or:
def helper_bar(vals):
for val in vals:
yield(foo(val))
{k: v for k, v in helper_bar(vals)}
However, none of these is very readable. Furthermore, if the list_of_vals is humongous I don't want to create extra copies. Is there any better (efficient?) way to do this assuming I have very long list of values and foo is an expensive function?
You can also use the dict initializator that takes an iterable of key-value tuples. So this would be perfect for your function that already returns a tuple:
>>> dict(map(foo, list_of_vals))
{2: 200, 4: 400, 6: 600}
In general though, having a function that returns a key-value tuple with the identical key seems somewhat rare. Most commonly, you would just have a function that returns the value. In those cases you would use a dictionary comprehension like this:
{ x: foo(x) for x in list_of_vals }
Just convert the result of map to dict directly
>>> list_of_vals = [2, 4, 6]
>>> dict(map(foo, list_of_vals))
{2: 200, 4: 400, 6: 600}
This question already has an answer here:
deleting entries in a dictionary based on a condition
(1 answer)
Closed 6 years ago.
Suppose I have an OrderedDict od with integer keys and integer values. I want to iterate over od and delete elements of od based on the value I find. Basically what I want to achieve is:
od = {1: 2, 2: 4, 3: 5}
for key in od:
del od[key]
In the end I want od to be equal to {1: 2, 3: 5}. Python does not allow to change the size of an OrderedDict during its iteration. Is it possible to overcome this problem?
I am working with Python 3.5
That is because you can not modify the length of dict while you are iterating over it. Instead you have to iterate over the copy of list of keys within the dict as:
# For both Python 3.x and 2.7
>>> for key in list(od):
... del od[key]
...
>>> od
{}
However in Python2.7, one may even use dict.keys() to get the same behavior:
# In Python 2.7
>>> for key in od.keys():
... del od[key]
...
>>> od
{}
this is the easiest way i know. enjoy!
With dicts, you can't change the length of the dictionary. however, what you can do is make a list copy of the original dictionary and use that to iterate through the original dictionary. as shown below
od = {'a': 2, 'b': 4, 'c': 5}
for key in list(od):
if key == 'b':
print(key)
del od[key]
print(od)
I think this what you mean to do
od = {1: 2, 2: 4, 3: 5}
for key in od.copy(): # iterate over a copy
if key in od and od[key] in od: # check for both key, 'target' key
del od[od[key]] # then delete the target with indirect indexing
od
Out[52]: {1: 2, 3: 5}
I have some code that iterates over the values of a dictionary. If the value meets certain conditions, it is deleted from the dictionary. Those conditions are contingent on the existence of other values in the dictionary. This is why I don't want to just copy the old dictionary and make deletions, then re-attribute it.
When I try to run it, I get an error that the size of the dictionary changed while iterating it.
Is there a way to iterate over a dictionary that allows it to change size, and the existence of keys and values, while it is iterating?
Build a new dictionary which contains the keys you want to keep. This can be done with a dictionary comprehension, or a manual for loop.
Here's a comprehension:
return {k: v for k, v in my_dict.items() if some-condition}
Here's a manual loop:
result = {}
for k, v in my_dict.items():
if some-condition:
result[k] = v
return result
Well, yes you can iterate on by the keys (Python3)! Take a look:
>>> dc
{1: 'aze', 3: 'poi', 4: 'mlk'}
>>> dc = {1:"aze", 2:"qsd", 3:"poi", 4:"mlk"}
>>> dc
{1: 'aze', 2: 'qsd', 3: 'poi', 4: 'mlk'}
>>> keys = list(dc.keys())
>>> keys
[1, 2, 3, 4]
>>> for k in keys:
if "q" in dc[k]:
del dc[k]
>>> dc
{1: 'aze', 3: 'poi', 4: 'mlk'}
>>>
You can iterate over the keys instead of over the dict itself. In the following example, all values that are odd-numbered are removed from the dict:
>>> a = {'a': 12, 'b': 3, 'c': 14}
>>> for key in list(a.keys()):
if a[key] % 2 == 0:
del a[key]
>>> a
{'b': 3}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
If I have a dictionary of dictionaries, of arbitrary depth, how could I list all of the keys that are in the dictionary, at a given depth? or get a list of the keys in the dictionary and their depths?
For example, a simple dictionary would be:
dict_o_dicts = {'a': {1:'bob', 2: 'fred', 3: 'henry'},
'b': {2:'fred',3: 'henry', 4: 'pascale'}
}
and I'd like a command that does something along the lines of:
print keys_at_depth(dict_o_dicts, 0)
would return: ['a', 'b'] and print keys_at_depth(dict_o_dicts, 1)
would return [1,2,3,4]
I can recursively walk the dictionary to find the maximum depth of the dictionary, but as soon as I try and report both the depth and the key values I end up breaking the recursion.
Thanks
This routine will recursively return a dictionary of sets of the keys at each depth:
def keys_by_depth(dict_, depth=0, output=None):
if output is None:
output = {}
if not depth in output:
output[depth] = set()
for key in dict_:
output[depth].add(key)
if isinstance(dict_[key], dict):
keys_by_depth(dict_[key], depth+1, output)
return output
Gives the output:
{0: {'b', 'a'}, 1: {1, 2, 3, 4}}
Note that this will work with a mix of dictionary and non-dict values at each level. For only keys at a given depth, you can call and access in one go:
>>> print(keys_by_depth(dict_o_dicts)[1])
{1, 2, 3, 4}
The assumption is that, all levels have valid dicts
dict_o_dicts = {'a': {1:'bob', 2: 'fred', 3: 'henry'},
'b': {2:'fred',3: 'henry', 4: 'pascale'} }
from itertools import chain
def keys_at_depth(d, l):
if l == 0: return d.keys()
elif l > 0: return set(chain.from_iterable([keys_at_depth(d[k], l - 1) for k in d]))
print keys_at_depth(dict_o_dicts, 1)
Output
set([1, 2, 3, 4])
Recursive approach:
def key_at_depth(dct, dpt):
if dpt > 0:
return [
key
for subdct in dct.itervalues()
for key in key_at_depth(subdct, dpt - 1)
]
else:
return dct.keys()
dict_o_dicts = {
'a': {1: 'bob', 2: 'fred', 3: 'henry'},
'b': {2: 'fred', 3: 'henry', 4: 'pascale'},
}
key_at_depth(dict_o_dicts, 0)
Out[69]: ['a', 'b']
key_at_depth(dict_o_dicts, 1)
Out[70]: [1, 2, 3, 2, 3, 4]
It seems you are working with a tree structure and you want obtain the nodes given a level. Reading your post, I realized may exists more dictionaries at the same level. So the solution I post here returns all the keys of all dictionaries at the given level.
keys=[]
def keys_at_level(tree, level):
# TODO: Eliminate that ugly global var keys.
if level == 0: # Adjust this contition to your needs (0 or 1)
# Calculate keys.
global keys
keys.extend(tree.keys())
else:
# Iter throught values and ask for dicts.
values = tree.values()
for value in values:
if isinstance(value, dict):
keys_at_level(value, level-1)
keys_at_level(tree, 0)
print keys
# If you don't want duplicates just do:
keys = set(keys)