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

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)

Related

In a list of list of list, how to compare list of list with the same alphabet and append the values into a new list?

I got two list of list of list:
A=[[[0, 'a'], [2, 'g'], [9, 'Q']], [[2, 'a'], [0, 'c'], [0, 'g'], [15, 'w'], [2, 'Q']], [[15, 'g'], [0, 'w'], [7, 'Q']], [[9, 'a'], [0, 'c'], [2, 'g'], [7, 'w'], [0, 'Q']]]
B[[[0, 'a'], [0, 'Q'], [12, 'front'], [0, 'Z']], [[1, 'a'], [2, 'c'], [0, 'w'], [0, 'Q'], [2, 'front'], [0, 'Z']], [[0, 'Q'], [3, 'front'], [5, 'Z']], [[12, 'a'], [0, 'c'], [2, 'w'], [3, 'Q'], [0, 'front'], [2, 'Z']], [[0, 'a'], [0, 'c'], [0, 'w'], [5, 'Q'], [2, 'front'], [0, 'Z']]]
For every list of list in it,I want to compare the alphabets.If the alphabets are in common append the list with the highest value number into the new list.If the alphabets are not in common,just append.
Output should be like:
C=[[[0, 'a'],[2,'g'], [9, 'Q'], [12, 'front'], [0, 'Z']], [[1, 'a'],[[0,'g'], [2, 'c'], [0, 'w'], [0, 'Q'], [2, 'front'], [0, 'Z']],....
Ignoring the order of the output nested list elements and assuming length of input lists are equal:
A=[[[0, 'a'], [2, 'g'], [9, 'Q']], [[0, 'c'], [0, 'g'], [0, 'Q']], [[2, 'a'], [0, 'c'], [0, 'g'], [15, 'w'], [2, 'Q']], [[15, 'g'], [0, 'w'], [7, 'Q']], [[9, 'a'], [0, 'c'], [2, 'g'], [7, 'w'], [0, 'Q']]]
B=[[[0, 'a'], [0, 'Q'], [12, 'front'], [0, 'Z']], [[1, 'a'], [2, 'c'], [0, 'w'], [0, 'Q'], [2, 'front'], [0, 'Z']], [[0, 'Q'], [3, 'front'], [5, 'Z']], [[12, 'a'], [0, 'c'], [2, 'w'], [3, 'Q'], [0, 'front'], [2, 'Z']], [[0, 'a'], [0, 'c'], [0, 'w'], [5, 'Q'], [2, 'front'], [0, 'Z']]]
C=[]
for index in range(len(A)):
list_a = A[index]
list_b = B[index]
if len(list_a) > len(list_b):
loop_list=list_a
comp_list=list_b
else:
loop_list=list_b
comp_list=list_a
temp=[]
found_list=[]
for each_sub_list in loop_list:
number = each_sub_list[0]
alphabet = each_sub_list[1]
found=0
for index_b,each_sub_list_b in enumerate(comp_list):
if alphabet == each_sub_list_b[1]:
found=index_b
found_list.append(comp_list[index_b])
break
if found:
if number > comp_list[found][0]:
temp.append(each_sub_list)
else:
temp.append(comp_list[found])
else:
temp.append(each_sub_list)
never_found_list = [item for item in comp_list if item not in found_list]
temp.extend(never_found_list)
C.append(temp)
print(C)
Lots of missing details needed to solve this correctly.
For example,
In which order do you append items when a letter is higher in list 2?
Does that matter?
Are you just trying to solve this one case, or do you need a solution
that works for any 3d lists?
"If the alphabets are not in common,just append"...HOW?
Anyways, hope this points you in the right direction. Definitely not optimized and I'm sure there is a much simpler and elegant recursive way of approaching this problem. But the idea is breaking it down so you are comparing the right elements, and then doing any necessary list appends.
a = [[[0, 'a'], [2, 'g'], [9, 'Q']], [[0, 'c'], [0, 'g'], [0, 'Q']], [[2, 'a'], [0, 'c'], [0, 'g'], [15, 'w'], [2, 'Q']], [[15, 'g'], [0, 'w'], [7, 'Q']], [[9, 'a'], [0, 'c'], [2, 'g'], [7, 'w'], [0, 'Q']]]
b = [[[0, 'a'], [0, 'Q'], [12, 'front'], [0, 'Z']], [[1, 'a'], [2, 'c'], [0, 'w'], [0, 'Q'], [2, 'front'], [0, 'Z']], [[0, 'Q'], [3, 'front'], [5, 'Z']], [[12, 'a'], [0, 'c'], [2, 'w'], [3, 'Q'], [0, 'front'], [2, 'Z']], [[0, 'a'], [0, 'c'], [0, 'w'], [5, 'Q'], [2, 'front'], [0, 'Z']]]
group_a = {}
group_b = {}
count = 0
for x in a:
group_a[count] = []
for y in x:
group_a[count].append(y)
count+=1
count = 0
for x in b:
group_b[count] = []
for y in x:
group_b[count].append(y)
count+=1
new_list = []
for x in range(len(group_b)):
first = group_a[x]
second = group_b[x]
for y in first:
for z in second:
if y[1] == z[1]:
if y[0] > z[0]:
break
else:
y[0] = z[0]
for y in second:
add = True
for z in first:
if y[1] == z[1]:
add = False
if add:
first.append(y)
new_list.append(first)
print(new_list)
Hopefully this helps you find that beautiful recursive solution that will work on all 3d lists, not just the two you provided above!
....and of course DRY (unlike what I did) in the better solution you come up with.
use itertools.izip_longest for handling different input list length, use itertools.zip_longest if you are using python 3.
tmp holding the zip item from both list
Then, sorted the list based on index 1 follow by index 0 key in reverse order, item with alphabat will be group together in order of value from high to low.
Then, we only take the 1st highest value item and ignore lower value item
A=[[[0, 'a'], [2, 'g'], [9, 'Q']], [[2, 'a'], [0, 'c'], [0, 'g'], [15, 'w'], [2, 'Q']], [[15, 'g'], [0, 'w'], [7, 'Q']], [[9, 'a'], [0, 'c'], [2, 'g'], [7, 'w'], [0, 'Q']]]
B=[[[0, 'a'], [0, 'Q'], [12, 'front'], [0, 'Z']], [[1, 'a'], [2, 'c'], [0, 'w'], [0, 'Q'], [2, 'front'], [0, 'Z']], [[0, 'Q'], [3, 'front'], [5, 'Z']], [[12, 'a'], [0, 'c'], [2, 'w'], [3, 'Q'], [0, 'front'], [2, 'Z']], [[0, 'a'], [0, 'c'], [0, 'w'], [5, 'Q'], [2, 'front'], [0, 'Z']]]
C = []
for a,b in itertools.izip_longest(A,B):
tmp = []
mem = set()
if a:
tmp.extend(a)
if b:
tmp.extend(b)
sorted_list = sorted(tmp, key=lambda x:(x[1],x[0]), reverse=True)
inner_out = []
for i in sorted_list:
if i[1] not in mem:
inner_out.append(i)
mem.add(i[1])
C.append(inner_out)
# C = [[[2, 'g'], [12, 'front'], [0, 'a'], [0, 'Z'], [9, 'Q']], [[15, 'w'], [0, 'g'], [2, 'front'], [2, 'c'], [2, 'a'], [0, 'Z'], [2, 'Q']], [[0, 'w'], [15, 'g'], [3, 'front'], [5, 'Z'], [7, 'Q']], [[7, 'w'], [2, 'g'], [0, 'front'], [0, 'c'], [12, 'a'], [2, 'Z'], [3, 'Q']], [[0, 'w'], [2, 'front'], [0, 'c'], [0, 'a'], [0, 'Z'], [5, 'Q']]]

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

working with a list vs a list created by a function

I have the following list "mylist" for which i created "foundkeys" function to search it for occurrence of another list "keys" items , The output will look like "formatted_list" now i pass the output of "foundkeys" to "reorder" function which reorders the content of passed "order" example of "foundkeys" into specific format .
The problem
If i use the the above setup i don't get the exact output needed but if i pass '"formatted_list"' "which is the exact output of "foundkeys" ", to "reorder" instead of calling "foundkeys" , i would get the needed format
the correct output should be like this :
with 'a' key having its elements starting with 'a' and 'k' key having its elements starting with 'k'
[['a', [[1, 'a', 'Asfoor', 'b', 'c'],
[2, 'a', 'j', 'deek', 'k'],
[3, 'a', 'k', 'bata', 'p']]],
['k', [[2, 'k', 'j', 'a', 'deek'],
[3, 'k', 'bata', 'a', 'p'],
[4, 'k', 'v', 'm', 'farkha']]]]
but if i use the setup i get the this wrong output:
where it puts 'k' instead of 'a' in elements of of the 'a' key
[['a', [[1, 'a', 'Asfoor', 'b', 'c'],
[2, 'k', 'j', 'deek', 'a'],
[3, 'k', 'a', 'bata', 'p']]],
['k', [[2, 'k', 'j', 'deek', 'a'],
[3, 'k', 'a', 'bata', 'p'],
[4, 'k', 'v', 'm', 'farkha']]]]
kindly have a look into the code for better understanding.
mylist=
[[1, 'Asfoor', 'a', 'b', 'c'],
[2, 'deek', 'j', 'a', 'k'],
[3, 'bata', 'k', 'a', 'p'],
[4,'farkha','v','m','k']]
keys = ['a', 'k']
def foundkeys(mylist,keys):
def found(list, k):
return k in list
final = []
for j in keys:
final.append([j , [k for k in mylist if found(k, j)]])
return final;
order=foundkeys(mylist,keys)
print("New list with found keys \n",order)
formatted_list=
[
[
'a', [[1, 'Asfoor', 'a', 'b', 'c'], [2, 'deek', 'j', 'a', 'k'], [3, 'bata', 'k', 'a', 'p']
]],
[
'k', [[2, 'deek', 'j', 'a', 'k'], [3, 'bata', 'k', 'a', 'p'], [4, 'farkha', 'v', 'm', 'k']]
]
]
def reorder(alist):
for item in alist:
key=item[0]
value=item[1]
for c,v_item in enumerate(value):
old=value[c][1]
for i,s_value in enumerate(value[c]):
if s_value==key:
value[c][i]=old
value[c][1]=key
# calling reorder function with order function list
reorder(order)
print(order)
# calling reorder function with formatted_list instead
reorder(formatted_list)
print(formatted_list)
Python use references to store the lists. To see this, try running the following code.
a = [1, 2]
b = [a for i in range(0, 3)]
print(b) # prints out [[1, 2], [1, 2], [1, 2]]
b[0][0] = 4
print(b) # prints out [[4, 2], [4, 2], [4, 2]]
[a for i in range(0, 3)] does not insert three "individual" a into b. It actually insert a's reference into b. So when we change an element through b[0][0], we change all the lists with the same reference.
To solve this, just ask python to create a new list, not just copying the reference.
a = [1, 2]
b = [list(a) for i in range(0, 3)] # This line is different
print(b) # prints out [[1, 2], [1, 2], [1, 2]]
b[0][0] = 4
print(b) # prints out [[4, 2], [1, 2], [1, 2]]
So in your code, it should be
for j in keys:
final.append([j , [list(k) for k in mylist if found(k, j)]])
And now you will get the same result using order and formatted_list.
You can see this post for more understanding about references and copies.

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)

Categories