Switching keys of a dictionary without switching the values - python

Let's say I have a dictionary like below
myDict = {"a": 1, "b": 2, "c": 3, "d": 4}
and I'm trying to get this result
myDict = {"b": 1, "a": 2, "c": 3, "d": 4}
I tried running using
dictionary[new_key] = dictionary.pop(old_key)
But thats just deleting and appending a new key and value to the dictionary. It would result in:
myDict = {"b": 2, "c": 3, "d": 4, "a": 2}
Thanks in advance for the answer

So I understand you aim to preserve the sequence.
Make first a new dictionary that maps the old keys to the new keys:
mapping = {"a": "b", "b": "a"}
Now you can generate the new structure
my_dict = {mapping.get(key, key): value for key, value in my_dict.items()}
The get method here tries to map the key, but uses the key itself, if the key is not in the mapping.

Related

How to get the max value from a dictionary inside of a dictionary?

I have a dictionary that looks like this
a_dictionary = {"a": {"green_count: 12"}, "b": {"green_count: 13"}, "c": {"green_count: 2"}}
How can I find the highest green_count value and return the key 'b'?
I know how to do this for a value directly inside a dictionary key max_key = max(a_dictionary, key=a_dictionary.get however I don't know how to do this for a value that is inside a dictionary in a dictionary.
Assuming you really have a nested dictionary (and thus that you syntax is incorrect):
a_dictionary = {"a": {"green_count": 12}, "b": {"green_count": 13}, "c": {"green_count": 2}}
max(a_dictionary, key=lambda x: a_dictionary[x].get('green_count',0))
Output: 'b'
You could try with a NestedDict. Install ndicts first
pip install ndicts
Then
from ndicts.ndicts import NestedDict
a_dictionary = {"a": {"green_count": 12}, "b": {"green_count": 13}, "c": {"green_count": 2}}
nd = NestedDict(a_dictionary)
maximum = max(nd.values())
This works with nested dictionaries of any depth.

In Python, how do I find keys in an array of dictionaries where the values are the same?

I'm using Python 3.8. I have an array of dictionaries, all of which have the same keys ...
list_of_dicts = [{"a": 1, "b": 2}, {"a": 1, "b": "zz"}, {"a": 1, "b": "2"}]
How do I return a list of keys in which all the values are identical? For example, the above would be just
["a"]
since all three dicts have "a" = 1.
Here is my additional answer of #JaonHax.
array_of_dicts = [{"a": 1, "b": 2}, {"a": 1, "b": "zz", "c": "cc"}, {"a": 1, "b": "2"}]
def get_same_vals(dicts):
keys = []
for key in dicts[0].keys():
is_same = True
for each_dict in array_of_dicts:
if not key in each_dict or each_dict[key] != dicts[0][key]:
is_same = False
if is_same:
keys.append(key)
return keys
print(get_same_vals(array_of_dicts))
As suggested in other answers, create a master dictionary that groups each key, then check their uniqueness.
# all keys are the same, so get the list
keys = array_of_dicts[0].keys()
# collapse values into a single dictionary
value_dict = {k: set(d[k] for d in array_of_dicts) for k in keys}
# get list of all single-valued keys
print([k for k, v in value_dict.items() if len(v) == 1])
If you know for certain that they all have the same keys, you can iterate through their keys and the list like so:
array_of_dicts = [{"a": 1, "b": 2}, {"a": 1, "b": "zz"}, {"a": 1, "b": "2"}]
def get_same_vals(dicts):
keys = []
for key in dicts[0].keys():
is_same = True
for each_dict in dicts:
if each_dict[key] != dicts[0][key]:
is_same = False
if is_same:
keys.append(key)
return keys
print(get_same_vals(array_of_dicts))
# Prints ['a']
I apologise for the inefficient code; I didn't spend that long coding this up.
Here's a possible solution, it will work also in case that the dictionaries are differently structured (have different / extra keys):
array_of_dicts = [{"a": 1, "b": 2}, {"a": 1, "b": "zz"}, {"a": 1, "b": "2"}]
def is_entry_in_all_dicts(key, value):
identical_entries_found = 0
for dict in array_of_dicts:
if key in dict:
if dict[key] == value:
identical_entries_found += 1
if identical_entries_found == len(array_of_dicts):
return True
return False
result = []
for dict in array_of_dicts:
for key, value in dict.items():
if is_entry_in_all_dicts(key, value):
if key not in result:
result.append(key)
print(result)
Output
['a']
If every dictionary has the same keys, you can combine the values into sets and find the sets with one element:
[list(x.keys())[0] for x in [{k:set([e[k] for e in list_of_dicts])} for k in list_of_dicts[0]] if len(list(x.values())[0]) == 1]
Output:
['a']
Append your N dictionaries into a giant dictionary, and check for keys that have N identical values:
giant_dict = collections.defaultdict(list)
for k, v in (e for d in list_of_dicts for e in d):
giant_dict[k].append(v)
for k, v in giant_dict.items():
if len(v) == len(list_of_dicts) and all(e == v[0] for e in v):
print(k)
Here's a more succinct approach
from functools import reduce
array_of_dicts = [{"a": 1, "b": 2}, {"a": 1, "c": "zz"}, {"a": 1, "d": "2"}]
result = reduce(lambda a, b: a.intersection(b),list(map(lambda x: set(x.keys()),
array_of_dicts)))
Group your values into a set, then figure out which keys have a set with length 1:
>>> from collections import defaultdict
>>> list_of_dicts = [{"a": 1, "b": 2}, {"a": 1, "b": "zz"}, {"a": 1, "b": "2"}]
>>> grouped_values = defaultdict(set)
>>> for d in list_of_dicts:
... for k,v in d.items():
... grouped_values[k].add(v)
...
>>> [k for k,v in grouped_values.items() if len(v) == 1]
['a']

Append elements from external dict into dict inside assignment [duplicate]

This question already has answers here:
How do I merge two dictionaries in a single expression in Python?
(43 answers)
Closed 4 years ago.
Hello, everyone.
Is there a way in python to insert all items from one dictionary to another inside variable assignment?
dict1 = {"a": 1, "b": 2, "c": 3}
dict2 = {"d": 4, #INSERT THERE ALL FROM "dict1"#, "e": -1}
Maybe there's smth like {key: value for key, value in temp.items()} or other "hack"?
I know that there's update() method and I've already applied it, but it looks a bit weird. Order of entries matters so to build dict in proper order I need to write next code :
dict1 = {"a": 1, "b": 2, "c": 3}
dict2 = {"d: 4"}
dict2.update(dict1)
dict2.update({"e": -1, "f": -2})
Hope there's a way to do it more "nice".
dict2 = {"d": 4, **dict1, "e": -1}

Adding multiple values to an existing dictionary as SETS

I have a dictionary where I have the data already inside, i.e. keys have values and some of them have more than one value.
For example:
i = {"a": "111", "b": "222", "c": ["333", "444"]}
How can I change the type of the multiple values? I want them to be sets, not lists, such as:
i = {"a": {"111"}, "b": {"222"}, "c": {"333", "444"}}
One similar post is this one:
How to add multiple values to a dictionary key in python? [closed]
There it is explained how to add multiple elements to a dictionary, but they always seem to be lists.
How to change the type of the multiple values?
OR how to add them to the dictionary as sets, not lists?
Using a dict-comprehension makes converting an existing dict very easy:
i = {"a": "111", "b": "222", 'c': ["333", "444"]}
{k: set(v) if isinstance(v, list) else v for k, v in i.items()}
this converts all values that are lists to sets.
In a single line of code:
>>> i = {"a": "111", "b": "222", "c": ["333", "444"]}
>>> {k: set(v) for k, v in i.items()}
{'b': {'2'}, 'a': {'1'}, 'c': {'444', '333'}}
Or with a few more steps:
>>> i = {"a": "111", "b": "222", "c": ["333", "444"]}
>>> for k, v in i.items():
... i[k] = set(v)
>>> i
{'b': {'2'}, 'a': {'1'}, 'c': {'444', '333'}}
Instead of doing
my_dict['key'] = ['333', '444']
use a set literal:
my_dict['key'] = {'333', '444'}
That looks like a dict literal, but the lack of key: value like things makes it a set.

Iterate over a list inside a nested dictionary

Lets say I have a dictionary like this:
myDict = {
1: {
"a": "something",
"b": [0, 1, 2],
"c": ["a", "b", "c"]
},
2: {
"a": "somethingElse",
"b": [3, 4, 5],
"c": ["d", "e", "f"]
},
3: {
"a": "another",
"b": [6, 7, 8],
"c": ["g", "h", "i"]
}
}
And this is my code:
for id, obj in myDict.items():
for key, val in obj.items():
if key is "b":
for item in val:
# apply some function to item
Is there a better way to iterate over a list inside a nested dict? Or is there a pythonic way to do this?
You absolutely do not need to iterate the list to print it (unless this is a functional requirement for the code you are writing).
Very simply, you could do this:
for id, obj in myDict.items():
if "b" in obj:
print obj["b"]
To map the list object, represented by obj['b'] to another function, you can use the map function:
map(foo, obj["b"])
If you're dictionary is always two levels deep, I don't see anything wrong with your approach. In your implementation, I would use key == "b" rather than key is "b". Using is will test for identity (e.g. id(a) == id(b)), while == will test for equality (e.g. a.__eq__(b)). This functions the same way when I test it in IDLE, but it's not a good habit to get into. There's more info on it here: How is the 'is' keyword implemented in Python?
If you want to deal with varying level dictionaries, you could use something like:
def test_dict_for_key(dictionary, key, function):
for test_key, value in dictionary.items():
if key == test_key:
dictionary[key] = type(value)(map(function, value))
if isinstance(value, dict):
test_dict_for_key(value, key, function)
An example usage might be something like:
myDict = {
1: {
"a": "something",
"b": [0, 1, 2],
"c": ["a", "b", "c"]
},
2: {
"a": "somethingElse",
"b": [3, 4, 5],
"c": ["d", "e", "f"]
},
3: {
"a": "another",
"b": [6, 7, 8],
"c": ["g", "h", "i"]
}
}
# adds 1 to every entry in each b
test_dict_for_key(myDict, "b", lambda x: x + 1)
# prints [1, 2, 3]
print(myDict[1]["b"])
I'm a fan of generator expressions.
inner_lists = (inner_dict['b'] for inner_dict in myDict.values())
# if 'b' is not guaranteed to exist,
# replace inner_dict['b'] with inner_dict.get('b', [])
items = (item for ls in inner_lists for item in ls)
Now you can either use a foo loop
for item in items:
# apply function
or map
transformed_items = map(func, items)
A couple fixes could be made.
Don't use is when comparing two strings (if key is "b":)
Simply say print(item) instead of using .format(), since you only have one variable that you're printing, with no additional string formatting
Revised code:
for id, obj in myDict.items():
for key, val in obj.items():
if key == "b":
for item in val:
print(item)
If you are sure that you will have a b key in every case, you can simply do:
for id, obj in myDict.items():
for item in obj["b"]:
print item

Categories

Resources