"How to unevenly iterate over two lists" - python

I cannot find a solution for this very specific problem I have.
In essence, I have two lists with two elements each: [A, B] and [1,2]. I want to create a nested loop that iterates and expands on the second list and adds each element of first list after each iteration.
What I want to see in the end is this:
A B
1 A
1 B
2 A
2 B
1 1 A
1 2 A
2 1 A
2 2 A
1 1 B
1 2 B
2 1 B
2 2 B
1 1 1 A
1 1 2 A
...
My problem is that my attempt at doing this recursively splits the A and B apart so that this pattern emerges (note the different first line, too):
A
1 A
2 A
1 1 A
1 2 A
2 1 A
2 2 A
1 1 1 A
1 1 2 A
...
B
1 B
2 B
1 1 B
1 2 B
2 1 B
2 2 B
1 1 1 B
1 1 2 B
...
How do I keep A and B together?
Here is the code:
def second_list(depth):
if depth < 1:
yield ''
else:
for elements in [' 1 ', ' 2 ']:
for other_elements in list (second_list(depth-1)):
yield elements + other_elements
for first_list in [' A ', ' B ']:
for i in range(0,4):
temp=second_list(i)
for temp_list in list(temp):
print temp_list + first_list

I would try something in the following style:
l1 = ['A', 'B']
l2 = ['1', '2']
def expand(l1, l2):
nl1 = []
for e in l1:
for f in l2:
nl1.append(f+e)
yield nl1[-1]
yield from expand(nl1,l2)
for x in expand(l1, l2):
print (x)
if len(x) > 5:
break
Note: the first line of your output does not seem to be the product of the same rule, so it is not generated here, you can add it, if you want, manually.
Note2: it would be more elegant not to build the list of the newly generated elements, but then you would have to calculate them twice.

Related

Can multiple table be formed from a condition in dataframe in python?

I have a dataset:
list1 list2
0 [1,3,4] [4,3,2]
1 [1,3,2] [0,4,6]
2 [4,5,8] NA
3 [6,3,7] [8,2,3]
Is there a process where i can find the count of the common term for- each of the index,
Expected output:
intersection_0, it will compare 0 of list1 with each of list2 and give output, intersection_1 which will compare 1 of list1 with each of list2
Expected_output:
Intersection_0 intersection_1 intersection_2 intersection_3
1 2 1 1
1 0 1 1
0 0 0 0
1 2 0 1
For intersection i was trying:
df['intersection'] = [len(set(a).intersection(b)) for a, b in zip(df1.list1, df1.list2)]
Is there a better way or faster way to achieve this? Thank you in advance
The double loop would go like this:
intersections = []
for l2 in df['list2']:
intersection = []
for l1 in df['list1']:
try:
i = len(np.intersect1d(l1,l2))
except:
i = 0
intersection.append(i)
intersections.append(intersection)
out = (pd.DataFrame(intersections))
Output:
0 1 2 3
0 2 2 1 1
1 1 0 1 1
2 0 0 0 0
3 1 2 1 1

Python: Change row and colum in a matrix

matrix = []
for index, value in enumerate(['A','C','G','T']):
matrix.append([])
matrix[index].append(value + ':')
for i in range(len(lines[0])):
total = 0
for sequence in lines:
if sequence[i] == value:
total += 1
matrix[index].append(total)
unity = ''
for i in range(len(lines[0])):
column = []
for row in matrix:
column.append(row[1:][i])
maximum = column.index(max(column))
unity += ['A', 'C', 'G', 'T'][maximum]
print("Unity: " + unity)
for row in matrix:
print(' '.join(map(str, row)))
OUTPUT:
Unity: GGCTACGC
A: 1 2 0 2 3 2 0 0
C: 0 1 4 2 1 3 2 4
G: 3 3 2 0 1 2 4 1
T: 3 1 1 3 2 0 1 2
With this code I get this matrix but I want to form the matrix like this:
A C G T
G: 1 0 3 3
G: 2 1 3 1
C: 0 4 2 1
T: 2 2 0 3
A: 3 1 1 2
C: 2 3 2 0
G: 0 2 4 1
C: 0 4 1 2
But I don't know how. I hope someone can help me. Thanks already for the answers.
The sequences are:
AGCTACGT
TAGCTAGC
TAGCTACG
GCTAGCGC
TGCTAGCC
GGCTACGT
GTCACGTC
You're needing to do a transpose of your matrix. I've added comments in the code below to explain what has been changed to make the table.
matrix = []
for index, value in enumerate(['A','C','G','T']):
matrix.append([])
# Don't put colons in column headers
matrix[index].append(value)
for i in range(len(lines[0])):
total = 0
for sequence in lines:
if sequence[i] == value:
total += 1
matrix[index].append(total)
unity = ''
for i in range(len(lines[0])):
column = []
for row in matrix:
column.append(row[1:][i])
maximum = column.index(max(column))
unity += ['A', 'C', 'G', 'T'][maximum]
# Tranpose matrix
matrix = list(map(list, zip(*matrix)))
# Print header with tabs to make it look pretty
print( '\t'+'\t'.join(matrix[0]))
# Print rows in matrix
for row,unit in zip(matrix[1:],unity):
print(unit + ':\t'+'\t'.join(map(str, row)))
The following will be printed:
A C G T
G: 1 0 3 3
G: 2 1 3 1
C: 0 4 2 1
T: 2 2 0 3
A: 3 1 1 2
C: 2 3 2 0
G: 0 2 4 1
C: 0 4 1 2
I think that the best way is to convert your matrix to pandas dataframe and to then use transpose function.
https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.transpose.html

Python index in nested for loop

I can put it in another example:
q=[[100,101,103,104],[201,202,204],[301,302,304],[401,402,403]]
for index, item in enumerate(q):
for i,t in enumerate(q[index]):
if q[index][i+1]-q[index][i]==2:
print index, i, q[index][i]
which returns
0 1 101
it supposed to return
0 1 101
1 1 202
2 1 302
it seems the break statement break the loop so it stops at the first list.
if I modify it by
for index, item in enumerate(q):
try:
for i range(len(q[index]-1)):
if q[index][i+1]-q[index][i]==2:
print index, i, q[index][i]
except IndexError:
break
Of course it is good, but I still want to know if there is a way that not to have to reduce the index as the last item is valuable as well.
To iterate through list of list you may use this code:
p=[['a','b','c','d'],
['a','c','e','d'],
['a','b','z','x']]
for i,item in enumerate(p):
for j,x in enumerate(item):
print i,j,x
Output:
0 0 a
0 1 b
0 2 c
0 3 d
1 0 a
1 1 c
1 2 e
1 3 d
2 0 a
2 1 b
2 2 z
2 3 x
for index,item in enumerate(p):
print 'top', index #The index is at this level
for x in range(len(item)):
print 'loop' ,index # Not this level where you print it.

Transpose nested generators

Is there a clear way to iterate over items for each generator in a list? I believe the simplest way to show the essence of the question is o proved an expample. Here it is
0. Assume we have an function returning generator:
def gen_fun(hint):
for i in range(1,10):
yield "%s %i" % (hint, i)
1. Clear solution with straight iteration order:
hints = ["a", "b", "c"]
for hint in hints:
for txt in gen_fun(hint):
print(txt)
This prints
a 1
a 2
a 3
...
b 1
b 2
b 3
...
2. Cumbersome solution with inverted iterating order
hints = ["a", "b", "c"]
generators = list(map(gen_fun, hints))
any = True
while any:
any = False
for g in generators:
try:
print(next(g))
any = True
except StopIteration:
pass
This prints
a 1
b 1
c 1
a 2
b 2
...
This works as expected and does what I want.
Bonus points:
The same task, but gen_fun ranges can differ, i.e
def gen_fun(hint):
if hint == 'a':
m = 5
else:
m = 10
for i in range(1,m):
yield "%s %i" % (hint, i)
The correct output for this case is:
a 1
b 1
c 1
a 2
b 2
c 2
a 3
b 3
c 3
a 4
b 4
c 4
b 5
c 5
b 6
c 6
b 7
c 7
b 8
c 8
b 9
c 9
The querstion:
Is there a way to implement case 2 cleaner?
If i understand the question correctly, you can use zip() to achieve the same thing as that whole while any loop:
hints = ["a", "b", "c"]
generators = list(map(gen_fun, hints))
for x in zip(*generators):
for txt in x:
print(txt)
output:
a 1
b 1
c 1
a 2
b 2
...
UPDATE:
If the generators are of different length, zip 'trims' them all to the shortest. you can use itertools.izip_longest (as suggested by this q/a) to achieve the opposite behaviour and continue yielding until the longest generator is exhausted. You'll need to filter out the padded values though:
hints = ["a", "b", "c"]
generators = list(map(gen_fun, hints))
for x in zip_longest(*generators):
for txt in x:
if txt:
print(txt)
You might want to look into itertools.product:
from itertools import product
# Case 1
for tup in product('abc', range(1,4)):
print('{0} {1}'.format(*tup))
print '---'
# Case 2
from itertools import product
for tup in product(range(1,4), 'abc'):
print('{1} {0}'.format(*tup))
Output:
a 1
a 2
a 3
b 1
b 2
b 3
c 1
c 2
c 3
---
a 1
b 1
c 1
a 2
b 2
c 2
a 3
b 3
c 3
Note that the different between case 1 and 2 are just the order of parameters passed into the product function and the print statement.

Python: print without overwriting printed lines

I have
for i in range(0, 11): print i, "\n", i
I'd like my python program to print this way for each for loop
1st loop:
1
1
2nd loop:
1
2
2
1
3rd loop:
1
2
3
3
2
1
I've tried using \r\n or \033[1A but they just overwrite the previous line. Is there a way I can "push" the outputted line down so I don't overwrite it?
One way to do this,
def foo(x, limit):
if x < limit :
print x
foo(x + 1, limit)
print x
foo(1, 11)
It's not possible to do it in 1 for loop as you're currently trying.
As I suggested, you can do it like this by using lists
>>> l1 = []
>>> l2 = []
>>> for i in range(0, 11):
... l1.append(i)
... l2 = [i] + l2
>>> l1.extend(l2)
>>> for i in l1:
... print i
0
1
2
3
4
5
6
7
8
9
10
10
9
8
7
6
5
4
3
2
1
0
Concatenation of two list generators.
>>> ladder = [x for x in range(5)] + [x for x in range(5,-1,-1)]
>>> ladder
[0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0]
>>> for x in ladder:
... print x
...
0
1
2
3
4
5
4
3
2
1
0
>>>
one of ways to solve this
def two_side_print(start, end):
text = [str(i) for i in range(start,end)]
print '\n'.join(text), '\n', '\n'.join(reversed(text))
two_side_print(1, 11)
Another option is to save the printed values in a list and print that list in reverse order in each loop iteration.
My suggestion:
l = []
for i in range(1, 5):
print 'Loop '+str(i) # This is to ease seeing the printing results
for val in l:
print val
print i
l.insert(len(l),i)
for val in reversed(l):
print val
The output for a loop iterating from 0 to 5:
Loop 1
1
1
Loop 2
1
2
2
1
Loop 3
1
2
3
3
2
1
Loop 4
1
2
3
4
4
3
2
1
I hope this is what you are looking for.
You can use a recursive function to help here:
def print_both_ways(start, end):
print(start)
if start != end:
print_both_ways(start+1, end)
print(start)
Usage:
print_both_ways(1,3) # prints 1,2,3,3,2,1 on separate lines

Categories

Resources