How to write Dictionary from list with Duplicate Keys - python

Would like to convert list into dictionary, but here I have duplicate keys and it should not be considered in output_dict.
Following is input list and expected dictionary.
input_list = [[1,'a'],[1,'b'],[2,'c'],[2,'d']]
output_dict = {
1:['a','b'],
2:['c','d']
}
Wrote following programme and it gives desired result but somehow feel that it is not standard way of doing things in python. Any other way to write this ?
from pprint import pprint
output_dict = {}
list2 = []
input_list = [[1,'a'],[1,'b'],[2,'c'],[2,'d']]
keys = []
for i in input_list:
keys.append(i[0])
for key in keys:
list2 = []
for i in input_list:
if key in i:
list2.append(i[1])
output_dict[key] = list2
print("\n\n")
pprint(output_dict)

You can use collections.defaultdict or use dict.setdefault to have shorter code:
input_list = [[1, "a"], [1, "b"], [2, "c"], [2, "d"]]
out = {}
for k, v in input_list:
out.setdefault(k, []).append(v)
print(out)
Prints:
{1: ['a', 'b'], 2: ['c', 'd']}

I would suggest using set() to remove the duplicates from the list and then append it into a dictionary!
input_list = list(set(input_list))

Related

Comparing nested list with dictionary keys, create compound key 'a+b' with sum of values

I have a nested list and I want to compare list items with dictionary keys and if match is found the corresponding dictionary values should be summed and appended to same dictionary as new key-value pair.
l1 = [['a','b'], ['c','d']]
dict1 = {'a':10, 'e':20, 'c':30, 'b':40}
Expected result:
dict1 = {'a':10, 'e':20, 'c':30, 'b':40, 'a+b':50, 'a+c':40, 'b+c':70}
What I have done so far:
for x in range(len(l1)):
for y in range(len(l1[x])):
for k in dict1.keys():
if k == l1[x][y]:
dict1.append(dict1[k])
Is there any way to do this without using nested for loops?
PS: code is not complete yet.
Presuming there is no importance to your nested lists e.g. l1 can be changed to ["a", "b", "c", d"] you can use itertools here.
First flatten l1 with itertools.chain
import itertools
l2 = itertools.chain(*l1)
(or l2 = itertools.chain.from_iterable(l1)).
Then loop through all combinations of two elements
for i, j in itertools.combinations(l2, 2):
if i in dict1 and j in dict1:
dict1[f"{i}+{j}"] = dict1[i] + dict1[j]
All together
import itertools
l1 = [['a','b'], ['c','d']]
dict1 = {'a':10, 'e':20, 'c':30, 'b':40}
for i, j in itertools.combinations(itertools.chain(*l1), 2):
if i in dict1 and j in dict1:
dict1[f"{i}+{j}"] = dict1[i] + dict1[j]
dict1 will now equal
{'a': 10, 'e': 20, 'c': 30, 'b': 40, 'a+b': 50, 'a+c': 40, 'b+c': 70}
you can try the below code
dict1 = {'a':10, 'e':20, 'c':30, 'b':40, 'a+b':50, 'a+c':40, 'b+c':70}
dict2={}
dict2['a+b']=dict1['a']+dict1['b']
dict2['a+c']=dict1['a']+dict1['c']
dict2['b+c']=dict1['b']+dict1['c']
dict1.update(dict2)
print(dict1)
Something like the following, using generators:
NOTE: OP if you don't clarify the question I'll delete this
d = {'a':10, 'e':20, 'c':30, 'b':40}
l1 = [['a','b'], ['c','d']]
def _gen_compound_keys(d, kk):
"""Generator helper function for the single and ocmpound keys from input tuple of keys"""
# Note: you can trivially generalize this from assuming fixed length of 2
yield kk[0], d[kk[0]]
yield kk[1], d[kk[1]]
yield '+'.join(kk), sum(d[k] for k in kk)
def gen_compound_keys(d, kk):
"""Generator for the single and compound keys, returns a dictionary as desired"""
return {k:v for k,v in _gen_compound_keys(d, kk)}
result = {}
result.update(gen_compound_keys(d, l1[0]))
result.update(gen_compound_keys(d, l1[1]))
result.update(d)

How to replace items in list with a keys from dictionary in Python

I have a dictionary
my_dict = {"a":1, "b":2, "c":3}
And list
my_list = [2,3,1]
I want to replace items in my_list with keys from my_dict, something like...
my_list = [b, c, a]
How can i achieve this?
I'm sure it's possible to manufacture a list comprehension but this could be one approach (which only ever iterates over the list once and allows you to cover potential edge cases inside the loop):
for key, value in my_dict.items():
if value not in my_list:
# Does this case need special handling?
continue
index = my_list.index(value)
my_list[index] = key
There are a few edge cases to consider here, e.g. what happens if not all items match, what if the dictionary and list are of unequal lengths etc. Depending on your use case you want to make sure to cover all possible edge cases accordingly.
Applied to your example code, it yields the following output:
>>> my_dict = {"a":1, "b":2, "c":3}
>>> my_list = [2,3,1]
>>> my_dict
{'a': 1, 'b': 2, 'c': 3}
>>> my_list
[2, 3, 1]
>>> for key, value in my_dict.items():
... if value not in my_list:
... # Does this case need special handling?
... continue
... index = my_list.index(value)
... my_list[index] = key
>>> my_list
['b', 'c', 'a']
Dictionaries are mappings. You want to use reverse mappings (use values to find keys), so let's reverse the dict.
my_dict = {"a":1, "b":2, "c":3}
reversed_dict = {my_dict[k]:k for k in my_dict}
Then we just apply the dict to each element:
my_list = [2,3,1]
result = [reversed_dict[elem] for elem in my_list]
You can reverse the key value pair of your dict and then iterate your list to get the corresponding keys.
>>> rev_dict = dict((v,k) for k,v in my_dict.items())
>>> rev_dict
{1: 'a', 2: 'b', 3: 'c'}
>>> [rev_dict[x] for x in my_list]
['b', 'c', 'a']
rev = { v:k for k,v in my_dict.items()}
new_list = [rev[item] for item in my_list]
Output new_list:
['b', 'c', 'a']
This will probably work
for key, val in my_dict.items():
for i, v in enumerate(my_list):
if v == val:
my_list[i] = key
You can do this with list comprehension, what you need to do is: sort the dict.items according to your list, then return the key:
>>> my_dict = {"a":1, "b":2, "c":3}
>>> my_list = [2,3,1]
>>> [key for key, value in sorted(my_dict.items(), key = lambda x:my_list.index(x[1]))]
['b', 'c', 'a']
You can use the function itemgetter. First, you need to swap keys and values in your dictionary:
from operator import itemgetter
dct = {"a": 1, "b": 2, "c": 3}
lst = [2, 3, 1]
dct = {v: k for k, v in dct.items()}
# {1: 'a', 2: 'b', 3: 'c'}
print(list(itemgetter(*lst)(dct)))
# ['b', 'c', 'a']

Popping the EXACT same value from a dictionary

I have a general list with information:
lis = ["Hello", "Hello1", "Test"]
Then I have a dictionary with filepathes to .c files as values and keys are extensions of the lis values like:
dict1 = {"/****Hello****/":
["C://test/hello/one.c",
"C://test/hello/two.c"],
"/****Hello1****/":
["C://test/helloNext/one.c",
"C://test/helloNext/two.c"],
"/****Test****/":
["C://test/bye/one.c",
"C://test/bye/two.c"]}
The idea is to replace the keys of dict1 with the values of lis, if values of lis are in the key information.
for x in lis:
for y in dict1.copy():
if x in y:
dict1[x] = dict1.pop(y)
As far as good but now I found a big problem:
If I do it that way, some information of dict1 are overwritten because in this example, it searches for a key with "Hello" in it and overwrites dict1[0] but also overwrites dict1[1] to "Hello" instead of "Hello1" because it's the first information...
I don't get to a solution on my own.
I think I am just missing a little bit...
Thanks!
PS: It is not a solution to just cut out special characters from the keys, because it does not look the same for every file..
One way would be to sort the list based on the length of the elements and process it in the reverse order:
lis = ["Hello", "Hello1", "Test"]
dict1 = {"/****Hello****/": ["C://test/hello/one.c", "C://test/hello/two.c"],
"/****Hello1****/": ["C://test/helloNext/one.c", "C://test/helloNext/two.c"],
"/****Test****/": ["C://test/bye/one.c", "C://test/bye/two.c"]}
for x in sorted(lis, key=len, reverse=True):
for y in dict1:
if x in y and y not in lis:
dict1[x] = dict1.pop(y)
break
print(dict1)
# {'Hello1': ['C://test/helloNext/one.c', 'C://test/helloNext/two.c'], 'Hello': ['C://test/hello/one.c', 'C://test/hello/two.c'], 'Test': ['C://test/bye/one.c', 'C://test/bye/two.c']}
You can sort your first list by descending length and then create a copy of your original dictionary, moving each element from the first to the new dict.
In [1]:
llist = ["a", "aa", "ab", "c"]
dict1 = {"xax": 1, "xaax": 2, "xabx": 3, "xabcx": 4}
llist.sort(key=len, reverse=True)
dict2 = dict()
for key in dict1:
success = False
for replace_token in llist:
if replace_token in key:
dict2[replace_token] = dict1.get(key)
success = True
break
if not success:
dict2[key] = dict1.get(key)
print(dict2)
Out [1]:
{'a': 1, 'aa': 2, 'ab': 4}
The general problem is in my code, as well as in your example. It is overwriting all previous values. So I suppose those values shall be in a list:
In [1]:
from typing import List
llist = ["a", "aa", "ab", "c"]
dict1 = {"xax": 1, "xaax": 2, "xabx": 3, "xabcx": 4}
llist.sort(key=len, reverse=True)
dict2 = dict()
for key in dict1:
success = False
for replace_token in llist:
if replace_token in key:
current = dict2.get(replace_token, [])
new = dict1.get(key)
if isinstance(new, List):
current.extend(new)
else:
current.append(new)
dict2[replace_token] = current
success = True
break
if not success:
dict2[key] = dict1.get(key)
print(dict2)
Out [1]:
{'a': [1], 'aa': [2], 'ab': [3, 4]}
You can use re.findall:
import re
lis = ["Hello","Hello1","Test"]
dict1 = {"/****Hello****/": ["C://test/hello/one.c", "C://test/hello/two.c"], "/****Hello1****/": ["C://test/helloNext/one.c", "C://test/helloNext/two.c"], "/****Test****/": ["C://test/bye/one.c", "C://test/bye/two.c"]}
_lis = sorted(lis, key=len, reverse=True)
new_dict = {re.findall('|'.join(_lis), a)[0]:b for a, b in dict1.items()}
Output:
{'Hello': ['C://test/hello/one.c', 'C://test/hello/two.c'], 'Hello1': ['C://test/helloNext/one.c', 'C://test/helloNext/two.c'], 'Test': ['C://test/bye/one.c', 'C://test/bye/two.c']}
import re
lis = ["Hello","Hello1","Test"]
dict1 = {"/****Hello****/": ["C://test/hello/one.c", "C://test/hello/two.c"],
"/****Hello1****/": ["C://test/helloNext/one.c", "C://test/helloNext/two.c"],
"/****Test****/": ["C://test/bye/one.c", "C://test/bye/two.c"]}
dict2 = {}
for x in lis:
print('x:',x)
for y in dict1.copy():
y2 = (y.replace('*', ''))
y2 = (y2.replace('/', ''))
if x == y2:
print(x,y2)
dict2[x] = dict1[y]
print(dict2)
Alternative: no using dict2
if x == y2:
print(x,y2)
dict1[x] = dict1[y]
del dict1[y]
OUTPUT
{'Hello': ['C://test/hello/one.c', 'C://test/hello/two.c'], 'Hello1': ['C://test/helloNext/one.c', 'C://test/helloNext/two.c'], 'Test': ['C://test/bye/one.c', 'C://test/bye/two.c']}

Python. Adding multiple items to keys in a dict

I am trying to build a dict from a set of unique values to serve as the keys and a zipped list of tuples to provide the items.
set = ("a","b","c")
lst 1 =("a","a","b","b","c","d","d")
lst 2 =(1,2,3,3,4,5,6,)
zip = [("a",1),("a",2),("b",3),("b",3),("c",4),("d",5)("d",6)
dct = {"a":1,2 "b":3,3 "c":4 "d":5,6}
But I am getting:
dct = {"a":1,"b":3,"c":4,"d":5}
here is my code so far:
#make two lists
rtList = ["EVT","EVT","EVT","EVT","EVT","EVT","EVT","HIL"]
raList = ["C64G","C64R","C64O","C32G","C96G","C96R","C96O","RA96O"]
# make a set of unique codes in the first list
routes = set()
for r in rtList:
routes.add(r)
#zip the lists
RtRaList = zip(rtList,raList)
#print RtRaList
# make a dictionary with list one as the keys and list two as the values
SrvCodeDct = {}
for key, item in RtRaList:
for r in routes:
if r == key:
SrvCodeDct[r] = item
for key, item in SrvCodeDct.items():
print key, item
You don't need any of that. Just use a collections.defaultdict.
import collections
rtList = ["EVT","EVT","EVT","EVT","EVT","EVT","EVT","HIL"]
raList = ["C64G","C64R","C64O","C32G","C96G","C96R","C96O","RA96O"]
d = collections.defaultdict(list)
for k,v in zip(rtList, raList):
d[k].append(v)
You may achieve this using dict.setdefault method as:
my_dict = {}
for i, j in zip(l1, l2):
my_dict.setdefault(i, []).append(j)
which will return value of my_dict as:
>>> my_dict
{'a': [1, 2], 'c': [4], 'b': [3, 3], 'd': [5, 6]}
OR, use collections.defaultdict as mentioned by TigerhawkT3.
Issue with your code: You are not making the check for existing key. Everytime you do SrvCodeDct[r] = item, you are updating the previous value of r key with item value. In order to fix this, you have to add if condition as:
l1 = ("a","a","b","b","c","d","d")
l2 = (1,2,3,3,4,5,6,)
my_dict = {}
for i, j in zip(l1, l2):
if i in my_dict: # your `if` check
my_dict[i].append(j) # append value to existing list
else:
my_dict[i] = [j]
>>> my_dict
{'a': [1, 2], 'c': [4], 'b': [3, 3], 'd': [5, 6]}
However this code can be simplified using collections.defaultdict (as mentioned by TigerhawkT3), OR using dict.setdefault method as:
my_dict = {}
for i, j in zip(l1, l2):
my_dict.setdefault(i, []).append(j)
In dicts, all keys are unique, and each key can only have one value.
The easiest way to solve this is have the value of the dictionary be a list, as to emulate what is called a multimap. In the list, you have all the elements that is mapped-to by the key.
EDIT:
You might want to check out this PyPI package: https://pypi.python.org/pypi/multidict
Under the hood, however, it probably works as described above.
Afaik, there is nothing built-in that supports what you are after.

removing duplicates from a list python

I have two lists:
list1 = [IM12345, IM12346, IM12347, IM12348]
list2 = [ID300, ID404, ID300, ID601]
list2 associates with the corresponding list1 values. list1 has unique values where as list2 has duplicates.
I want to make list2 unique corresponding associated value will add in the that list2 value.
Dict= {ID300: {IM12345, IM12347}, ID404: IM12346, ID601: IM12348}
Above pattern can be in list, set or dictionary.
Which algorithm in python should I use to get the above result?
You could try collections.defaultdict:
from collections import defaultdict
d = defaultdict(set)
list1 = ['IM12345', 'IM12346', 'IM12347', 'IM12348']
list2 = ['ID300', 'ID404', 'ID300', 'ID601']
for key, value in zip(list2, list1):
d[key].add(value)
Demo:
>>> d
defaultdict(<class 'set'>, {'ID300': {'IM12345', 'IM12347'}, 'ID404': {'IM12346'}, 'ID601': {'IM12348'}})
>>>
>>>
>>> for i, j in d.items():
... print(i, j)
...
...
ID601 {'IM12348'}
ID300 {'IM12345', 'IM12347'}
ID404 {'IM12346'}
You can create a dict to save the dataset
list1 = ["IM12345", "IM12346", "IM12347", "IM12348"]
list2 = ["ID300", "ID404", "ID300", "ID601"]
dictResult=dict()
i=0
for item in list2:
print item
if dictResult.has_key(item):
dictResult[item].append(list1[i])
else:
dictResult[item]=[list1[i]]
i=i+1
print dictResult
Result:
{'ID404': ['IM12346'], 'ID300': ['IM12345', 'IM12347'], 'ID601': ['IM12348']}
Might not completely be a pythonic way but - here it goes:
Map the input:
map = dict(zip(list1, list2))
Now you can do an inverse mapping:
inv_map = {}
for k, v in map.iteritems():
inv_map[v] = inv_map.get(v, [])
inv_map[v].append(k)
Result for the example above:
>>> inv_map
{'ID404': ['IM12346'], 'ID300': ['IM12345', 'IM12347'], 'ID601': ['IM12348']}
Another way of doing it could be with list operations.
yourList = ["1","2","3","4","1","2"]
newList = []
for f in yourList:
if f not in newList:
newList.append(f)
Simple solution
from collections import defaultdict
list1 = ['IM12345', 'IM12346', 'IM12347', 'IM12348']
list2 = ['ID300', 'ID404', 'ID300', 'ID601']
d = defaultdict(list)
for n in range(len(list2)):
d[list2[n]].append(list1[n])
print d.items()
Result:
[('ID404', ['IM12346']), ('ID300', ['IM12345', 'IM12347']), ('ID601', ['IM12348'])]
Python2.7 Documentation----defaultdict

Categories

Resources