From nested for loop to dictionary comprehension? - python

I have a dictionary (dict_) with lists of integers as values.
I want to make an operation on these list and save the result as a new dictionary.
Below I do an operation on these list, adding 2 if the elements are larger than 5. I use a nested for loop to achieve this. How would I achieve the same using dictionary comprehension?
dict_={'a':[5, 8, 7],
'b':[4, 7, 2],
'c':[2, 2, 4]}
print(dict_)
#Output: {'a': [5, 8, 7], 'b': [4, 7, 2], 'c': [2, 2, 4]}
dict_new = {}
for k, v in dict_.items():
list_temp=[]
for e in v:
if e > 5:
ne=e + 2
list_temp.append(ne)
else:
list_temp.append(e)
dict_new[k] = list_temp
print(dict_new)
# Output: {'a': [5, 8, 7], 'b': [4, 7, 2], 'c': [2, 2, 4]}

this could be your dict-comprehension:
{k: [i if i <= 5 else i + 2 for item in v] for k, v in dict_.items()}
note that you need a list-comprehension for the values as well.
noting that False is basically 0 and True is 1 you could simplify (but maybe making it more obscure?) the list-comprehension:
{k: [i + 2 * (i > 5) for i in v] for k, v in dict_.items()}

You can do this, but as you are working with both dicts and lists, you will want to use a list comprehension also.
my_dict ={'a':[5, 8, 7],
'b':[4, 7, 2],
'c':[2, 2, 4]}
d = {key: [x if x <= 5 else x + 2 for x in value] for key, value in my_dict.items()}
This should solve the above problem and return:
{'a': [5, 10, 9], 'b': [4, 9, 2], 'c': [2, 2, 4]}

for k, v in dict_.items():
dict_new[k] = [e + 2 if e > 5 else e for e in v ]

Related

How to search/append a list within a dictionary

Say I have a dictionary comprised of integer keys, and a list of integers corresponding to each key.
myDict = {0:[1,2,3,4], 1:[1,2,3], 2:[3,4,5]}
How do I search the list in key 1 for the integer 4, and if it's not in the list append it so that 1:[1,2,3,4]
Try this:
myDict = {0:[1,2,3,4], 1:[1,2,3], 2:[3,4,5]}
# Only if k exists in 'dict'. We append value for that specific key
def search_append(d, k, v):
if (k in d) and (not v in d[k]):
d[k].append(v)
search_append(myDict, 1, 4)
print(myDict)
{0: [1, 2, 3, 4], 1: [1, 2, 3, 4], 2: [3, 4, 5]}
# if k is not in 'dict' we create a key and append the value
def search_append_2(d, k, v):
if not v in d.get(k, []):
d.setdefault(k, []).append(v)
search_append_2(myDict, 3, 4)
print(myDict)
# {0: [1, 2, 3, 4], 1: [1, 2, 3], 2: [3, 4, 5], 3: [4]}

Merging dictionaries not including duplicate values in python

I would like to merge two dictionaries, but if they have the same key, I would only merge non-duplicate values.
The following code works, but I have a question if it's possible to rewrite this when trying to get a union by using | or (**dict1, **dict2)? When I tried using |, my output would be from this dict_merge({ 'A': [1, 2, 3] }, { 'A': [2, 3, 4] }) to this {'A': [2, 3, 4]}
def dict_merge(dict1, dict2):
for key in dict2.keys():
if key in dict1.keys():
d3 = dict1[key] + dict2[key]
d3 = set(d3)
dict1[key] = list(d3)
else:
dict1[key] = dict2[key]
return dict1
dict_merge({ 'A': [1, 2, 3] }, { 'B': [2, 4, 5, 6]})
Output
{ 'A': [1, 2, 3], 'B': [2, 4, 5, 6] }
Giving your two dictionaries names, let's get the union of their keys.
>>> d1 = { 'A': [1, 2, 3] }
>>> d2 = { 'A': [2, 3, 4] }
>>> d1.keys() | d2.keys()
{'A'}
Assuming the lists are really sets based on your code, we can now iterate over the union of the keys in a dictionary comprehension, and union those two sets and turning them back into a list.
>>> {k: list(set(d1.get(k, [])) | set(d2.get(k, []))) for k in d1.keys() | d2.keys()}
{'A': [1, 2, 3, 4]}
If we incorporate some more interesting dictionaries and repeat the same dictionary comprehension:
>>> d1 = {'A': [1,2,3], 'B': [4,5,6]}
>>> d2 = {'B': [5,6,7,8], 'C': [9,10]}
>>> {k: list(set(d1.get(k, [])) | set(d2.get(k, []))) for k in d1.keys() | d2.keys()}
{'C': [9, 10], 'A': [1, 2, 3], 'B': [4, 5, 6, 7, 8]}
Is that the solution you're wanting?
In [61]: my_dict = {}
...: d1 = {'A': [1, 2, 3], 'C': 123}
...: d2 = {'B': [2, 3, 4], 'A': [1, 2, 3]}
...: for i in set(d1).symmetric_difference(set(d2)):
...: my_dict[i] = d1[i] if i in d1 else d2[i]
...: print(my_dict)
Output :
{'B': [2, 3, 4], 'C': 123}

Match dictionary keys and values in new dictionary

I trying to match keys and values in a dictionary together and put them into a new dictionary.
My initial dictionary looks like this:
d = {1: [5,6], 3: [4], 8: [2,3]}
I know that I can access keys and values using d.keys() and d.values().
My goal is to find all items which relate. I think it is best explained if I illustrate my desired output.
I wish to create a new dict that gives me:
finaldict = {1: [5,6], 2: [3,4,8], 3: [2,4,8], 4:[2,3,8] 5:[1,6], 6:[1,5], 8:[2,3,4]}
That is, I want to get keys of all numbers, and give values to what number they are related to.
My attempt:
d = {1: [5,6], 3:[4],8:[2,3]}
print(d)
keys = list(d.keys())
vals = list(d.values())
for i in range(0,len(d.keys())):
current_vals = list(vals[i])
length = len(current_vals)
for v in current_vals:
if v in d.keys(): #if the dictionary exists, then append
add = [keys[i],current_vals]
d[v].append(add)
else:
add2 = [keys[i],current_vals]
empty = []
for a in add2:
if type(a) == int:
empty.append(a)
if type(a) == list:
for b in a:
empty.append(b)
d[v] = empty
keys = list(d.keys())
vals = list(d.values())
for i in range(0,len(keys)):
if keys[i] in vals[i]:
vals[i].remove(keys[i])
finaldict = {}
for j in range(0,len(keys)):
finaldict[keys[j]] = vals[j]
print("Final dict:\n",finaldict)
My attempt gives me the output
Final dict:
{1: [5, 6], 3: [4, [8, [2, 3]]], 8: [2, 3], 5: [1, 6], 6: [1, 5], 4: [3], 2: [8, 3]}
As you can see, finaldict[3] has the values [4, [8, [2, 3,]]].
The values themselves are wrong (3 should not be there), and also I want this to be a single list, and not on the format it is now. There are also other issues, such as finaldict[2] having the values [8, 3] when it should, in fact, have the values [3, 4, 8] and finaldict[4] only having [3], when it should have [2, 3, 8].
Not the most beautiful code I've ever written, but here it goes.
I create sets with all the numbers that are related to each other, then create a dictionary of each of those numbers as key, with the other ones as values.
d = {1: [5,6], 3: [4], 8: [2,3]}
pools = []
for key,values in d.items():
for pool in pools:
if key in pool or any(val in pool for val in values):
pool.add(key)
[pool.add(val) for val in values]
break
else:
pools.append(set((key, *values)))
#pools = [{1, 5, 6}, {8, 2, 3, 4}]
finaldict = {k:set.difference(v, set((k,))) for pool in pools for k, v in zip(pool, [pool]*len(pool))}
print(finaldict)
You can use recursion:
d = {1: [5,6], 3: [4], 8: [2,3]}
def groups(v, seen = [], c = []):
if (k:=[i for a, b in d.items() for i in ({a, *b} if v in {a, *b} else []) if i not in {*seen, v}]):
for i in k:
yield from groups(i, seen=seen+[v], c = c+([v] if seen else []))
else:
yield c+[v]
r = {i:[*{j for k in groups(i) for j in k}] for a, b in d.items() for i in [a, *b]}
Output:
{1: [5, 6], 5: [1, 6], 6: [1, 5], 3: [8, 2, 4], 4: [8, 2, 3], 8: [2, 3, 4], 2: [8, 3, 4]}
You can build up the resulting dictionary by merging related groups and assigning the same merged group to every key that is part of it:
d = {1: [5,6], 3: [4], 8: [2,3]}
related = dict()
for key,group in d.items(): # merge/assign groups to keys
merged = set(group).union({key},*(related.get(k,[]) for k in group))
related.update((k,merged) for k in merged)
related = {k:list(g-{k}) for k,g in related.items()} # exclude key from group
print(related)
{1: [5, 6], 5: [1, 6], 6: [1, 5], 3: [8, 2, 4], 4: [8, 2, 3],
2: [8, 3, 4], 8: [2, 3, 4]}

how to multiply dictionary values which are multiples

How do I multiply the values of this dictionary by 2?
d = {'a': (1,2), 'y': (2,4), 'z': (10,3)}
I get this
for i in d:
print(d[i]*2)
[1, 2, 1, 2]
[2, 4, 2, 4]
[10, 3, 10, 3]
but I want to achieve:
[2,4]
[4,8]
[20,6]
You're attempting to multiply a tuple which is resulting in the duplication of the values in your tuple. Instead, to algebraically interact with your tuples, you must do so one value at a time.
for i in d:
print(d[i][0]*2, d[i][1]*2)
You need to iterate through dictionary values and multiply each element by 2, not tuples * 2:
d = {'a': (1,2), 'y': (2,4), 'z': (10,3)}
for x in d.values():
print([y*2 for y in x])
# [2, 4]
# [4, 8]
# [20, 6]
What you are doing is:
>>> tupl = (1, 2)
>>> tupl * 2
(1, 2, 1, 2)
Here you need to do list comprehension
d = {'a': (1,2), 'y': (2,4), 'z': (10,3)}
for k in d.keys():
d[k] = [2*x for x in d[k]]
print(d)
{'a': [2, 4], 'y': [4, 8], 'z': [20, 6]}

Summation of elements of dictionary that are list of lists

d = {
'a': [[1, 2, 3], [1, 2, 3]],
'b': [[2, 4, 1], [1, 6, 1]],
}
def add_element(lst):
ad = [sum(i) for i in zip(*lst)]
return ad
def csv_reducer2(dicty):
return {k: list(map(add_element, v)) for k, v in dicty.items()}
csv_reducer2(d)
required output:
{'b': [3, 10, 2], 'a': [2, 4, 6]}
Above is the code I have been trying but it gives an error
zip argument #1 must support iteration
>>> d = {'a': [[1, 2, 3], [1, 2, 3]], 'b': [[2, 4, 1], [1, 6, 1]]}
>>> {k: map(sum, zip(*v)) for k, v in d.items()}
{'a': [2, 4, 6], 'b': [3, 10, 2]}
The following will work on Python 2 or 3:
>>> {k: [a + b for a, b in zip(*v)] for k, v in d.items()}
{'a': [2, 4, 6], 'b': [3, 10, 2]}
The issue with your code is you are mapping add_element to every individual element in v inside your dictionary comprehension. This passes a one-dimensional list to zip in add_element, resulting in your error (since individual integers don't support iteration.
To fix your original code, the only change you need to make is:
return {k: list(map(add_element, v)) for k, v in dicty.items()}
->
return {k: add_element(v) for k, v in dicty.items()}
Because zip(*lst) is trying to transpose multiple rows into columns, but you are only passing it single rows through your original map

Categories

Resources