convert to list comprehension - python

this is my python code
mylist = ['a', 'f', 'z']
old_d = {'a': 'aaa', 'b': 'bbb', 'c': 'ccc', 'f': 'fff', 'g':'ggg', 'z':'zzz'}
new_d = {}
for key in mylist:
new_d[key] = old_d[key]
Can we write the above code using list comprehensions or something similar like
new_d[key] = old_d[key] for key in mylist

In Python 2.7 and above you can use a dict comprehension:
new_d = {key: old_d[key] for key in myList}
In Python 2.6 and below, you don't have dict comprehensions must use dict with a generator or list comprehension:
new_d = dict((key, old_d[key]) for key in myList)

new_d = {key: old_d[key] for key in mylist}

You can use dict comprehension on Python 2.7 and newer:
new_d = {k: old_d[k] for k in mylist}

Related

Sort dictionary values alphabetically, where the order of the keys is not important

I have just started learning dictionaries and I have a problem with one task that requires me to sort dictionary values alphabetically.
def sort_dictionary(dic: dict) -> dict:
for i, j in dic.items():
sorted_dict = {i: sorted(j)}
print(sorted_dict)
So, for example print(sort_dictionary({"b":["d", "a"], "a":["c", "f"]})) should give me {"b":["a", "d"], "a":["c", "f"]}. My code gives
{'b': ['a', 'd']}
{'a': ['c', 'f']}
How can this be fixed? Also, if possible, I will ask you not to use lambda, since I have not yet learned it.
Try:
def sort_dictionary(dic):
sorted_dict = {}
for i, j in dic.items():
sorted_dict[i] = sorted(j)
return sorted_dict
print(sort_dictionary({"b":["d", "a"], "a":["c", "f"]}))
# {'b': ['a', 'd'], 'a': ['c', 'f']}
In your current code, you are making sorted_dict with only one key, print it, and then throw it away at each iteration. You need to accumulate the "key: sorted list" pair at each iteration, and then return the complete dictionary at the end, after you finish the for loop.
Also, you need to return the dictionary, not print the dictionary in the function. The caller print(sort_dictionary(...)) would obtain the output from the function, and then print it. (When you run your own code, you will see the code prints None. It is because you didn't write return in your code; in this case the function automatically returns None.)
Later when you learn about list- and dict-comprehensions, you will find it easier and more readable to write:
def sort_dictionary(dic):
return {k: sorted(v) for k, v in dic.items()}
You can do in place sorting in the same dictionary:
def sort_dictionary(dic: dict) -> dict:
for i, j in dic.items():
j.sort()
print(dic)
You can use dict.update() to update the value:
def sort_dictionary(dic: dict) -> dict:
sorted_dict = dict()
for i, j in dic.items():
sorted_dict.update({i: sorted(j)})
return sorted_dict
print(sort_dictionary({"b":["d", "a"], "a":["c", "f"]}))
# {'b': ['a', 'd'], 'a': ['c', 'f']}
Or update while iterating it:
def sort_dictionary(dic: dict) -> dict:
for i, j in dic.items():
dic.update({i: sorted(j)})
return dic
print(sort_dictionary({"b":["d", "a"], "a":["c", "f"]}))
# {'b': ['a', 'd'], 'a': ['c', 'f']}

How to change the positions of a dictionary? [duplicate]

This question already has answers here:
Reverse / invert a dictionary mapping
(32 answers)
Closed 10 months ago.
I have a dictionary as follows:
d = {'a': ['b'], 'c': ['d']}
I want to change the positions of the dictionary so that it looks like the following:
d_new = {'b': 'a', 'd': 'c'}
I have tried the following, but due to the second term being a list in my original dictionary (d), I am unable to complete this.
d = {'a': ['b'], 'c': ['d']}
for k in list(d.keys()):
d[d.pop(k)] = k
print(d)
You can use iterable unpacking in a dict comprehension like so:
{v: k for k, (v,) in d.items()}
>>> d = {'a': ['b'], 'c': ['d']}
>>> {v: k for k, (v,) in d.items()}
{'b': 'a', 'd': 'c'}
This assumes all values are a list of one element and you only want the first element in the lists.
Otherwise you can use this more appropriate code:
{v[0] if isinstance(v, list) else v: k for k, v in d.items()}
A variation on a theme using list unpacking:
d = {'a': ['b'], 'c': ['d']}
d = {v: k for k, [v] in d.items()}
print(d)
In case the values (lists) happen to contain more than one element and you're only interested in the first element then:
d = {v:k for k, [v,*_] in d.items()}
Of course, this could also be used even if there's only one element per list

How to merge keys of dictionary which have the same value?

I need to combine two dictionaries by their value, resulting in a new key which is the list of keys with the shared value. All I can find online is how to add two values with the same key or how to simply combine two dictionaries, so perhaps I am just searching in the wrong places.
To give an idea:
dic1 = {'A': 'B', 'C': 'D'}
dic2 = {'D': 'B', 'E': 'F'}
Should result in:
dic3 = {['A', 'D']: 'B', 'C': 'D', 'E': 'F'}
I am not sure why you would need such a data structure, you can probably find a better solution to your problem. However, just for the sake of answering your question, here is a possible solution:
dic1 = {'A':'B', 'C':'D'}
dic2 = {'D':'B', 'E':'F'}
key_list = list(dic2.keys())
val_list = list(dic2.values())
r = {}
for k,v in dic1.items():
if v in val_list:
i = val_list.index(v) #get index at value
k2 = key_list[i] #use index to retrive the key at value
r[(k, k2)] = v #make the dict entry
else:
r[k] = v
val_list = list(r.values()) #get all the values already processed
for k,v in dic2.items():
if v not in val_list: #if missing value
r[k] = v #add new entry
print(r)
output:
{('A', 'D'): 'B', 'C': 'D', 'E': 'F'}
You can't assign a list as a key in a python dictionary since the key must be hashable and a list is not an ashable object, so I have used a tuple instead.
I would use a defaultdict of lists and build a reversed dict and in the end reverse it while converting the lists to tuples (because lists are not hashable and can't be used as dict keys):
from collections import defaultdict
dic1 = {'A':'B', 'C':'D'}
dic2 = {'D':'B', 'E':'F'}
temp = defaultdict(list)
for d in (dic1, dic2):
for key, value in d.items():
temp[value].append(key)
print(temp)
res = {}
for key, value in temp.items():
if len(value) == 1:
res[value[0]] = key
else:
res[tuple(value)] = key
print(res)
The printout from this (showing the middle step of temp) is:
defaultdict(<class 'list'>, {'B': ['A', 'D'], 'D': ['C'], 'F': ['E']})
{('A', 'D'): 'B', 'C': 'D', 'E': 'F'}
If you are willing to compromise from 1-element tuples as keys, the second part will become much simpler:
res = {tuple(value): key for key, value in temp.items()}

add a second value to a key (dict) python

I need to make sure I don't have more than one of the same keys, if so, leave the first one and add their value (make it a list) to the existing key
this is what I tried:
my_dict = {1: "A", 2: "B", 1: "C"}
new_dict={}
list_keys = list(my_dict.keys())
list_values = list(my_dict.values())
for i in range(len(list_values)):
if list_keys[i] in new_dict.keys():
new_dict[list_keys[i]].append(list(list_values[i]))
else:
new_dict.update({list_keys[i]: list_values[i]})
return new_dict
The result required:
{1: ["A", "C"], 2: ["B"]}
The most concise way of reversing a dict like that uses a defaultdict:
from collections import defaultdict
d = {"A": 1, "B": 2, "C": 1}
rev = defaultdict(list)
for k, v in d.items():
rev[v].append(k)
rev
# defaultdict(<class 'list'>, {1: ['A', 'C'], 2: ['B']})
That first line doesn't make sense. A dictionary cannot have two values for the same key, so when you run that first line, the resulting dictionary is:
my_dict = {1: 'A', 2: 'B', 1: 'C'}
print(my_dict)
# {1: 'C', 2: 'B'}
What you could do is iterate over lists of desired keys and values, and build the dictionary that you want that way:
my_keys = [1, 2, 1]
my_vals = ['A', 'B', 'C']
my_dict = {}
for k, v in zip(my_keys, my_vals):
if k in my_dict.keys():
if not isinstance(my_dict[k], list):
my_dict[k] = [my_dict[k]] # convert to a list
my_dict[k].append(v)
else:
my_dict[k] = v
print(my_dict)
# {1: ['A', 'C'], 2: 'B'}
Based on the comments, you originally had a dictionary in_dict = {'A': 1, 'B': 2, 'C':1}. Given this in_dict, you can get the desired result by setting my_keys = in_dict.values() and my_vals = in_dict.keys() in the code above.
Using comprehensions if you want
a = {"A":1, "B":2, "C":1}
{value: [item_[0] for item_ in a.items() if item_[1] == value] for value in set(a.values())}
Output
{1: ['A', 'C'], 2: ['B']}

Find same dictionary by value

I have dictionary like below
dict1 = {'a':{'a':20, 'b':30}, 'b':{'a':30, 'b':40}, 'c':{'a':20, 'b':30}, 'd':{'a':30, 'b':40}}
Then in following dictionary two dictionaries are same, so expected result will be like below
result = [['a','c'],['b','d']]
>>> seen = {}
>>> dict1 = {'a':{'a':20, 'b':30}, 'b':{'a':30, 'b':40}, 'c':{'a':20, 'b':30}, 'd':{'a':30, 'b':40}}
>>> for k in dict1:
fs = frozenset(dict1[k].items())
seen.setdefault(fs, []).append(k)
>>> seen.values() # note: unordered
[['a', 'c'], ['b', 'd']]
If order is needed:
>>> from collections import OrderedDict
>>> dict1 = {'a':{'a':20, 'b':30}, 'b':{'a':30, 'b':40}, 'c':{'a':20, 'b':30}, 'd':{'a':30, 'b':40}}
>>> seen = OrderedDict()
>>> for k in sorted(dict1):
fs = frozenset(dict1[k].items())
seen.setdefault(fs, []).append(k)
>>> seen.values()
[['a', 'c'], ['b', 'd']]
Note: This code is currently cross-compatible on Python 2/3. On Python 2 you can make it more efficient by using .iteritems() instead of .items()
A quick one: 1st get different values, then list comprehension.
>>> values = []
>>> for k in dict1:
if dict1[k] not in values:
values.append(dict1[k])
>>> values
[{'a': 20, 'b': 30}, {'a': 30, 'b': 40}]
>>> [[k for k in dict1 if dict1[k] == v] for v in values]
[['a', 'c'], ['b', 'd']]

Categories

Resources