Python, clustered two-column count - python

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))

Related

How to merge two dictionaries in a specific way?

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]]}

Adding an element to two elements in a list at a time

Not too sure how to build this, but I am trying to add one element from one list to another.
x = [1,1,2,2,3,3]
a=[['b'],['c'],['d'],['e'],['f'],['g'],['h'],['i'],['j'],['k'],['l'],['m']]
And I'm trying to get an output like this where it adds one element:
a=[['b',1],['c',1],['d',2],['e',2],['f',3],['g',3],['h',1],['i',1],['j',2],['k',2],['l',3],['m',3]]
This can be accomplished in native Python by using the mod operator:
x = [1,1,2,2,3,3]
a=[['b'],['c'],['d'],['e'],['f'],['g'],['h'],['i'],['j'],['k'],['l'],['m']]
results = [[value[0], x[index % len(x)]] for index, value in enumerate(a)]
print(results)
If you want to modify the lists, you can use a for loop and use itertools.cycle:
from itertools import cycle
for ai,xi in zip(a,cycle(x)):
ai.append(xi)
which gives:
>>> a
[['b', 1], ['c', 1], ['d', 2], ['e', 2], ['f', 3], ['g', 3], ['h', 1], ['i', 1], ['j', 2], ['k', 2], ['l', 3], ['m', 3]]
If you do not care about the original lists, you can also use list comprehension to construct a new list of lists:
a[:] = [ai+[xi] for ai,xi in zip(a,cycle(x))]
which gives:
>>> [ai+[xi] for ai,xi in zip(a,cycle(x))]
[['b', 1], ['c', 1], ['d', 2], ['e', 2], ['f', 3], ['g', 3], ['h', 1], ['i', 1], ['j', 2], ['k', 2], ['l', 3], ['m', 3]]

python: combine lists of lists for SQLITE table

I need to combine 3 lists into one list so that I can insert it smoothly into sqlite table.
list1= [[a1,b1,c1],[a2,b2,c2]]
list2= [[d1,e1,f1],[d2,e2,f2]]
Output should look like:
combined_list = [[a1,b1,c1,d1,e1,f1],[a2,b2,c2,d2,e2,f2]]
I tried sum list1 + list2 but both didn't work as this output.
You can try this:
from operator import add
a=[[1, 2, 3], [4, 5, 6]]
b=[['a', 'b', 'c'], ['d', 'e', 'f']]
print a + b
print map(add, a, b)
Output:
[[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], ['d', 'e', 'f']]
[[1, 2, 3, 'a', 'b', 'c'], [4, 5, 6, 'd', 'e', 'f']]
Edit:
To add more than two arrays:
u=[[]]*lists[0].__len__()
for x in lists:
u=map(add, u, x)

No repeat in itertools.combinations based on nested sequence element?

source=[['a', 1], ['b', 1], ['d', 2], ['e', 2], ['f',3]]
target=[list(x) for x in itertools.combinations(source,3)]
for i in target: print(i)
[['a', 1], ['b', 1], ['d', 2]]
[['a', 1], ['b', 1], ['e', 2]]
[['a', 1], ['b', 1], ['f', 3]]
[['a', 1], ['d', 2], ['e', 2]]
[['a', 1], ['d', 2], ['f', 3]]
[['a', 1], ['e', 2], ['f', 3]]
[['b', 1], ['d', 2], ['e', 2]]
[['b', 1], ['d', 2], ['f', 3]]
[['b', 1], ['e', 2], ['f', 3]]
[['d', 2], ['e', 2], ['f', 3]]
Can I have itertools.combinations not repeat by nested sequence element? In this case, element [1] of each nested sequence to produce:
[['a', 1], ['d', 2], ['f', 3]]
[['a', 1], ['e', 2], ['f', 3]]
[['b', 1], ['d', 2], ['f', 3]]
[['b', 1], ['e', 2], ['f', 3]]
Split out your input list into separate groups instead and produce their product. You could use itertools.groupby() if your input is sorted by the second parameter:
from itertools import groupby, product
from operator import itemgetter
source = [['a', 1], ['b', 1], ['d', 2], ['e', 2], ['f', 3]]
grouped = (list(group) for key, group in groupby(source, key=itemgetter(1)))
for combo in product(*grouped):
print(list(combo))
If you input is not sorted by the second parameter, you'd group them by using a dictionary:
source = [['a', 1], ['b', 1], ['d', 2], ['e', 2], ['f', 3]]
groups = {}
for item in source:
groups.setdefault(item[1], []).append(item)
grouped = [group for key, group in sorted(groups.items())]
where I assume you wanted to sort on that same second value to inform the final output order.
You can write a generator that filters the results:
import itertools
def my_combinations(*args, **kw):
for result in itertools.combinations(*args, **kw):
_,l = zip(*result)
if len(l) == len(set(l)):
yield result
source=[['a', 1], ['b', 1], ['d', 2], ['e', 2], ['f',3]]
target=[list(x) for x in my_combinations(source,3)]
for i in target: print(i)

Unpack a nested list

My question is simple.
There are two lists.
The first is a list of integers:
a = [1, 2, 3]
The other is a list of lists:
b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
How could I get the result below:
result = [[1, 'a', 'b'], [2, 'c', 'd'], [3, 'e', 'f']]
Thanks.
>>> a = [1, 2, 3]
>>> b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
>>> [[aa] + bb for aa, bb in zip(a, b)]
[[1, 'a', 'b'], [2, 'c', 'd'], [3, 'e', 'f']]
In Python3
>>> a = [1, 2, 3]
>>> b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
>>> [aa+bb for *aa, bb in zip(a,b)]
[[1, 'a', 'b'], [2, 'c', 'd'], [3, 'e', 'f']]
Another way to do this would be:
index = 0
l = b
for i in a:
l[index].append(i)
index += 1
The following Python code will unpack each list and assemble it in the form you indicated.
[[a[i]] + b[i] for i in range(min(len(a),len(b)))]
Using Python's enumerate function you can loop over a list with an index. Using x.extend(y) will prepend the values in list x to list y.
a = [1, 2, 3]
b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
result = []
for index, value in enumerate(a):
aa = [value]
aa.extend(b[index])
result.append(aa)

Categories