How to merge two dictionaries in a specific way? - python

I have a two dictionaries like:
d1 = {'new_list1':['a', 'b', 'c', 'd'], 'new_list2':['a', 'b', 'd', 'e']}
d2 = {'new_list1': [1,2,3,4], 'new_list2': [1,2,4,5]}
I want output like:
d3 = {'new_list1':[['a',1],['b',2],['c',3],['d',4]], 'new_list2':[['a',1],['b',2],['d',4],['e',5]]}
Points to See:
1. both the dictionaries will have same number of keys
2. values present in form of list can have different length, so padding as 0 will be required in case of mismatch

Try this :
d3 = dict(zip(d1.keys(),[list(zip(d1[k], d2[k])) for k in d1]))
Output :
{'new_list1': [('a', 1), ('b', 2), ('c', 3), ('d', 4)], 'new_list2': [('a', 1), ('b', 2), ('d', 4), ('e', 5)]}

If possible match each value between both lists of dictionaries use:
out = {k:list(map(list, zip(v, d2[k]))) for k, v in d1.items()}
print (out)
{'new_list1': [['a', 1], ['b', 2], ['c', 3], ['d', 4]],
'new_list2': [['a', 1], ['b', 2], ['d', 4], ['e', 5]]}
If lengths not match use zip_longest:
from itertools import zip_longest
d1 = {'new_list1':['a', 'b', 'c', 'd'], 'new_list2':['a', 'b']}
d2 = {'new_list1': [1,2,3], 'new_list2': [1,2,4,5]}
out = {k:list(map(list, zip_longest(v, d2[k], fillvalue=0))) for k, v in d1.items()}
Or:
out = {k: list(map(list, zip_longest(d1[k], d2[k], fillvalue=0))) for k in d1}
print (out)
{'new_list1': [['a', 1], ['b', 2], ['c', 3], ['d', 0]],
'new_list2': [['a', 1], ['b', 2], [0, 4], [0, 5]]}

An update to #jezrael answer. I don't think there is any need to typecast the result of map to a list.
from itertools import zip_longest
d1 = {'new_list1':['a', 'b', 'c', 'd'], 'new_list2':['a', 'b']}
d2 = {'new_list1': [1,2,3], 'new_list2': [1,2,4,5]}
out = {k:map(list, zip_longest(v, d2[k], fillvalue=0)) for k, v in d1.items()}
Or:
out = {k: map(list, zip_longest(d1[k], d2[k], fillvalue=0)) for k in d1}
print (out)
{'new_list1': [['a', 1], ['b', 2], ['c', 3], ['d', 0]],
'new_list2': [['a', 1], ['b', 2], [0, 4], [0, 5]]}

Related

Merging 2 arrays in Python

I have 2 arrays:
first_arr = ['A', 'B', 'C', 'D', 'E', 'F']
second_arr = [1, 2, 3, 4, 5, 6]
And I'd like to unite them to an array or a list like this:
third_arr = [['A',1], ['B',2], ['C',3], ['D',4], ['E',5], ['F',6]]
or my_list = [['A',1], ['B',2], ['C',3], ['D',4], ['E',5], ['F',6]]
What is the easiest way to do it?
You can use zip() to merge the arrays...
first_arr = ['A', 'B', 'C', 'D', 'E', 'F']
second_arr = [1, 2, 3, 4, 5, 6]
third_arr = list(zip(first_arr, second_arr))
print(third_arr)
Which results in...
[('A', 1), ('B', 2), ('C', 3), ('D', 4), ('E', 5), ('F', 6)]
There is no difference between ('A',1) and ['A',1] in most cases. However, if you want to, you can change then from tuples to lists by assigning third_arr to the following...
...
third_arr = [list(t) for t in zip(first_arr, second_arr)]
print(third_arr)
Which results in...
[['A', 1], ['B', 2], ['C', 3], ['D', 4], ['E', 5], ['F', 6]]
Starting with the two lists, you can create a third list joining the elements of the two lists using the method .append() in a for loop:
first_arr = ['A', 'B', 'C', 'D', 'E', 'F']
second_arr = [1, 2, 3, 4, 5, 6]
my_list = []
for i in range(0,len(first_arr)):
my_list.append([first_arr[i],second_arr[i]])
my_list
[['A', 1], ['B', 2], ['C', 3], ['D', 4], ['E', 5], ['F', 6]]

Python, clustered two-column count

I have the following list:
a = [['A','R.1',1],['B','R.2',1],['B','R.2',2],['C','R.2',3],
['C','C.1',4],['C','C.1',5],['A','C.1',8],['B','C.1',9],
['B','C.1',1],['A','R.3',2],['C','R.1',3],['A','R.2',4],
['C','R.1',5],['A','R.1',1],['C','R.2',5],['A','R.1',8]]
I need to somehow group it to generate the following result:
[['A', 'C.1', 1],
['A', 'R.1', 3],
['A', 'R.2', 1],
['A', 'R.3', 1],
['B', 'C.1', 2],
['B', 'R.2', 2],
['C', 'C.1', 2],
['C', 'R.1', 2],
['C', 'R.2', 2]]
Where the third column is count of rows where the first and second columns match.
From the original list the value of the third column is negligible.
I have already tried via "for" nested and "list comprehension", but I have not been able to come up with any results.
Does anyone have any clue how I can resolve this?
With collections.defaultdict object:
import collections
a = [['A','R.1',1],['B','R.2',1],['B','R.2',2],['C','R.2',3],
['C','C.1',4],['C','C.1',5],['A','C.1',8],['B','C.1',9],
['B','C.1',1],['A','R.3',2],['C','R.1',3],['A','R.2',4],
['C','R.1',5],['A','R.1',1],['C','R.2',5],['A','R.1',8]]
d = collections.defaultdict(int)
for l in a:
d[(l[0],l[1])] += 1
result = [list(k)+[v] for k,v in sorted(d.items())]
print(result)
The output:
[['A', 'C.1', 1], ['A', 'R.1', 3], ['A', 'R.2', 1], ['A', 'R.3', 1], ['B', 'C.1', 2], ['B', 'R.2', 2], ['C', 'C.1', 2], ['C', 'R.1', 2], ['C', 'R.2', 2]]
Just for "pretty" print:
import pprint
...
pprint.pprint(result)
The output:
[['A', 'C.1', 1],
['A', 'R.1', 3],
['A', 'R.2', 1],
['A', 'R.3', 1],
['B', 'C.1', 2],
['B', 'R.2', 2],
['C', 'C.1', 2],
['C', 'R.1', 2],
['C', 'R.2', 2]]
Similar to #RomanPerekhrest, I used a Counter:
from collections import Counter
a = [['A','R.1',1],['B','R.2',1],['B','R.2',2],['C','R.2',3],
['C','C.1',4],['C','C.1',5],['A','C.1',8],['B','C.1',9],
['B','C.1',1],['A','R.3',2],['C','R.1',3],['A','R.2',4],
['C','R.1',5],['A','R.1',1],['C','R.2',5],['A','R.1',8]]
def transform(table):
c = Counter(map(lambda c: tuple(c[:-1]), table))
return sorted(map(lambda p: list(p[0]) + [p[1]], c.items()))
print(transform(a))

Merging sublists into a list based on sublist item in python

Input:
I have this ordered list.
[[1, 'A'], [1, 'B'],[1, 'D'], [2, 'A'],[2,'D'], [3, 'C'], [4, 'D'], [5, 'B'], [6, 'D']]
Desired output
[[1,['A','B','D']],[2, ['A','D']], [3, 'C'], [4, 'D'], [5, 'B'], [6, 'D']]
Since the first item of those two sublists are same.
Also can i convert into a dictionary with a key and those values pair. Like
{1:['A','B','D'],2:['A','D'],3:['C']}
What is the easiest and simplest way to do this?
If the data is ordered, then itertools.groupby is a good approach:
>>> from itertools import groupby
>>> from operator import itemgetter
>>> data = [[1, 'A'], [1, 'B'], [2, 'A'], [3, 'C'], [4, 'D'], [5, 'B'], [6, 'D']]
>>> final_data = []
>>> final_data = []
>>> for k, g in groupby(data, itemgetter(0)):
... group = list(g)
... if len(group) == 1:
... final_data.append(group[0])
... else:
... final_data.append([k, [sub[1] for sub in group]])
...
>>> final_data
[[1, ['A', 'B']], [2, 'A'], [3, 'C'], [4, 'D'], [5, 'B'], [6, 'D']]
>>>
If you want the results in a dictionary, that is even easier:
>>> grouped_dict = {}
>>> for num, letter in data:
... grouped_dict.setdefault(num, []).append(letter)
...
>>> grouped_dict
{1: ['A', 'B'], 2: ['A'], 3: ['C'], 4: ['D'], 5: ['B'], 6: ['D']}
>>>
You can create the dictionary directly from the input.
from collections import defaultdict
input = [[1, 'A'], [1, 'B'],[1, 'D'], [2, 'A'],[2,'D'], [3, 'C'], [4, 'D'], [5, 'B'], [6, 'D']]
d = defaultdict(list)
for el in input: d[el[0]].append(el[1])
The output of d will be:
{1: ['A', 'B', 'D'], 2: ['A', 'D'], 3: ['C'], 4: ['D'], 5: ['B'], 6: ['D']}
If the order is not important, and you want dictionary anyway:
import collections
your_list = [[1,'A'], [1,'B'], [1,'D'], [2,'A'], [2,'D'], [3,'C'], [4,'D'], [5,'B'], [6,'D']]
result = collections.defaultdict(list)
for k, v in your_list:
result[k].append(v)
# {1: ['A', 'B', 'D'], 2: ['A', 'D'], 3: ['C'], 4: ['D'], 5: ['B'], 6: ['D']}
You can also do it without collections.defaultdict (probably at some performance penalty, in dependence of key frequency):
your_list = [[1,'A'], [1,'B'], [1,'D'], [2,'A'], [2,'D'], [3,'C'], [4,'D'], [5,'B'], [6,'D']]
result = {}
for k, v in your_list:
result[k] = result.get(k, []) + [v]
# {1: ['A', 'B', 'D'], 2: ['A', 'D'], 3: ['C'], 4: ['D'], 5: ['B'], 6: ['D']}
You can use groupby from itertools module like this example:
a = [[1, 'A'], [1, 'B'],[1, 'D'], [2, 'A'],[2,'D'], [3, 'C'], [4, 'D'], [5, 'B'], [6, 'D']]
final = []
for k, v in groupby(sorted(a, key=lambda x: x[0]), lambda x: x[0]):
bb = list(v)
if len(bb) > 1:
final.append([k, [j for _, j in bb]])
else:
final.append([k, bb[0][1]])
# OR:
# Within a list comprehension
# final = [[k, [j[1] for j in list(v)]] for k, v in groupby(sorted(a, key=lambda x: x[0]), lambda x: x[0])]
print(final)
Output:
[[1, ['A', 'B', 'D']],
[2, ['A', 'D']],
[3, 'C'],
[4, 'D'],
[5, 'B'],
[6, 'D']]
Then to convert the final list into a dict you can do:
final_dict = {k:v if isinstance(v, list) else [v] for k, v in final}
print(final_dict)
Output:
{1: ['A', 'B', 'D'], 2: ['A', 'D'], 3: ['C'], 4: ['D'], 5: ['B'], 6: ['D']}}
I found better do the opposite, instead of make a list and then a dictionary I made dictionary and then a list.
Input:
in_list = [[1, 'A'], [1, 'B'],[1, 'D'], [2, 'A'],[2,'D'], [3, 'C'], [4, 'D'], [5, 'B'], [6, 'D']]
Code:
mydict = {}
for sublist in in_list:
if sublist[0] in mydict.keys():
mydict[sublist[0]] = [*mydict[sublist[0]],sublist[1]]
else:
mydict[sublist[0]] = sublist[1]
Output:
>>> mydict
{1: ['A', 'B', 'D'], 2: ['A', 'D'], 3: 'C', 4: 'D', 5: 'B', 6: 'D'}
Make an easy list with the dictionary:
mylist = list(mydict.items())
Output:
>>> mylist
[(1, ['A', 'B', 'D']), (2, ['A', 'D']), (3, 'C'), (4, 'D'), (5, 'B'), (6, 'D')]
Make another list with the dictionary:
mylist = = [[k,v] for k,v in mydict.items()]
Same as:
mylist = []
for key, value in mydict.items():
Output:
>>> mylist
[[1, ['A', 'B', 'D']], [2, ['A', 'D']], [3, 'C'], [4, 'D'], [5, 'B'], [6, 'D']]
in_list
out_list = []
sublist = []
i = 0
for l in in_list:
if l[0] != i:
i = l[0]
sublist = []
out_list.append([i, sublist])
sublist.append(l[1])
dico = dict( out_list)
In the python documentation example, https://docs.python.org/2/library/collections.html#defaultdict-examples
they used solved same problems in your post.
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
then I voted an answer with defaultdict.
dic = {}
res_lst = []
lst = [[1, 'A'], [1, 'B'],[1, 'D'], [2, 'A'],[2,'D'], [3, 'C'], [4, 'D'], [5, 'B'], [6, 'D']]
convert into list pair
for lst_item in lst:
if lst_item[0] in dic:
for item in lst_item[1:]:
dic[lst_item[0]].append(item)
else:
dic[lst_item[0]] = lst_item[1:]
convert into key value pair
for item in dic:
lst1 = []
lst1.append(item)
if(len(dic[item]) == 1):
lst1.append(dic[item][0])
else:
lst1.append(dic[item])
res_lst.append(lst1)
print(res_lst)

How to merge two lists by index

I have two lists:
i = ['a', 'b', 'c']
x = [1,2,3]
i need to produce such dictionary:
xxx = { 'a': [a, 1],
'b': [b, 2],
'c': [c, 3]}
I have done this:
for indx in i:
for indx2 in x:
xxx.update({indx: [indx, indx2]})
but obvioulsy it doesnt work
Using dict comprehension:
>>> i = ['a', 'b', 'c']
>>> x = [1,2,3]
>>> {key: [key, value] for key, value in zip(i, x)}
{'a': ['a', 1], 'c': ['c', 3], 'b': ['b', 2]}
how about this, if tuple can be the value of your dict.
i= ['a', 'b', 'c']
x= [1, 2, 3]
dict(zip(i,zip(i,x)))
{'a': ('a', 1), 'b': ('b', 2), 'c': ('c', 3)}

extracting a range of elements from a csv / 2d array

I want to extract elements from a range of elements is a specific column from a csv file.
I've simplified the problem to this:
data = [['a',1,'A',100],['b',2,'B',200],['c',3,'C',300],['d',4,'D',400]]
print(data[0:2][:],'\nROWS 0&1')
print(data[:][0:2],'\nCOLS 1&1')
I thought that meant
'show me all columns for just row 0 and 1'
'show me all the rows for just column 0 and 1'
But the output is always just showing me rows 0 and 1, never the columns,
[['a', 1, 'A', 100], ['b', 2, 'B', 200]]
ROWS 0&1
[['a', 1, 'A', 100], ['b', 2, 'B', 200]]
COLS 1&1
when I want to see this:
['a', 1, 'A', 100,'b', 2, 'B', 200] # ... i.e. ROWS 0 and 1
['a','b','c','d',1,2,3,4]
Is there a nice way to do this?
Your problem here is that data[:] is just a copy of data:
>>> data
[['a', 1, 'A', 100], ['b', 2, 'B', 200], ['c', 3, 'C', 300], ['d', 4, 'D', 400]]
>>> data[:]
[['a', 1, 'A', 100], ['b', 2, 'B', 200], ['c', 3, 'C', 300], ['d', 4, 'D', 400]]
... so both your attempts at slicing are giving you the same result as data[0:2].
You can get just columns 0 and 1 with a list comprehension:
>>> [x[0:2] for x in data]
[['a', 1], ['b', 2], ['c', 3], ['d', 4]]
... which can be rearranged to the order you want with zip():
>>> list(zip(*(x[0:2] for x in data)))
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
To get a single list rather than a list of 2 tuples, use itertools.chain.from_iterable():
>>> from itertools import chain
>>> list(chain.from_iterable(zip(*(x[0:2] for x in data))))
['a', 'b', 'c', 'd', 1, 2, 3, 4]
... which can also be used to collapse data[0:2]:
>>> list(chain.from_iterable(data[0:2]))
['a', 1, 'A', 100, 'b', 2, 'B', 200]

Categories