How to loop by specific step - python

I have a nested loop data=
[[1,43,344,546],[2,34,45,565]....[10,1,1,1],
[1,15,111,151],[2,152,28,19]....[10,2,2,2],
[1,21,45,1647],[2,288,65,90]....[10,3,3,3]
.....]
so basically, all the inside lists can be grouped by 10lists with the first element always starting from 1 to 10. taking the every 10th list as a key, so I want to calculate a newlist by subtracting every list's number by the 10th list accordingly, for example
[[1,43-1,344-2,546-3], [2,34-1,45-2,565-3].... [10,1,2,3],
[1,15-21,111-22,151-23],[2,152-21,28-22,19-23]....[10,21,22,23],
[1,21-31,45-32,1647-33],[2,288-31,65-32,90-33]....[10,31,32,33]
.....]
My code seems don't work, can someone plz help with this? thanks
line = 0
while line <= (len(data) - 10):
for i in range(line, line + 10):
temp = data[i]
if temp[0] == 10: #find the every 10 th keys and store them to x, y, z
x = temp[1]
y = temp[2]
z = temp[3]
break
for sublist in data:
sublist[1] = sublist[1] - x# assign new elements to original list data
sublist[2] = sublist[2] - y
sublist[3] = sublist[3] - z
line += 10
return data

This is one way to do what you want
from pprint import pprint
def next_mul(n):
"returns next multiple of 10 greater than n"
return n + (10 - n % 10)
# sample data
data = [[i for i in range(4)] for i in range(20)]
for i in range(len(data)):
if i % 10 == 0:
continue
data[i-1][1:] = [k-l for k,l in zip(data[next_mul(i)-1][1:], data[i-1][1:])]
pprint(data)
Output (originally every sublist of data was just [0, 1, 2, 3]):
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 1, 2, 3],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 1, 2, 3]]
Hope this helps. Please let me know if there are any questions/concerns!

Related

Why do I get "pop index out of range" error when running this?

I am writing code to make a bot for the math game "Dandelions" and in order to do so, I take all columns, rows, and diagonals that contain the number 1. Then, with this list of lists that contain the number 1, I need to separate them using a for loop. However, when running this for loop I get an error saying that the pop index is out of range, but when I run the code with each individual i value, I don't get an error. It is the last for loop at the very end of the code that is causing this problem. Please help! Note: Even when running the for loop with a range of 3, it still outputs an error. Only indexes 0 and 2 are outputted.
row_1 = [0, 0, 0, 0, 0]
row_2 = [0, 1, 0, 0, 0]
row_3 = [0, 0, 0, 0, 0]
row_4 = [0, 0, 0, 0, 0]
row_5 = [0, 0, 0, 0, 0]
col_1 = [0, 0, 0, 0, 0]
col_2 = [0, 0, 1, 0, 0]
col_3 = [0, 0, 0, 0, 0]
col_4 = [0, 0, 0, 0, 0]
col_5 = [0, 0, 0, 0, 0]
#diagonals 1-9 go from left to right, while diagonals 10-18 go from right to left
dia_1 = [0]
dia_2 = [0, 0]
dia_3 = [0, 0, 0]
dia_4 = [0, 0, 0, 0]
dia_5 = [0, 0, 0, 1, 0]
dia_6 = [0, 0, 0, 0,]
dia_7 = [0, 0, 0]
dia_8 = [0, 0]
dia_9 = [0]
dia_10 = [0]
dia_11 = [0, 0]
dia_12 = [0, 0, 0]
dia_13 = [0, 0, 0, 0]
dia_14 = [0, 0, 0, 0, 1]
dia_15 = [0, 0, 0, 0,]
dia_16 = [0, 0, 0]
dia_17 = [0, 0]
dia_18 = [0]
dia = [dia_1, dia_2, dia_3, dia_4, dia_5, dia_6,
dia_7, dia_8, dia_9, dia_10, dia_11, dia_12,
dia_13, dia_14, dia_15, dia_16, dia_17, dia_18]
row = [row_1, row_2, row_3, row_4, row_5]
col = [col_1, col_2, col_3, col_4, col_5]
possible = []
for i in dia:
if 1 in i:
possible.append(i)
for i in row:
if 1 in i:
possible.append(i)
for i in col:
if 1 in i:
possible.append(i)
for i in range(0, 4):
print(possible.pop(i))
The for loops that are giving you the out-of-range error wrap them on a try-except block, in the exception add new logic to ignore or fix the out of range; for instance:
try:
for i in range(0, 4):
print(possible.pop(i))
except:
#correct your out-of-range:
pass
Seems you did not get my hint and the only answer so far is not very helpful.
To reproduce the problem, let's hard-code possible, since everything before the last loop does not really matter.
possible = [[0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]]
print(f"Possible before loop: {possible}")
for i in range(0, 4):
print(f"Item at pos {i}: {possible.pop(i)}")
print(f"Possible after pop: {possible}")
Output:
Possible before loop: [[0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]]
Item at pos 0: [0, 0, 0, 1, 0]
Possible after pop: [[0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]]
Item at pos 1: [0, 1, 0, 0, 0]
Possible after pop: [[0, 0, 0, 0, 1], [0, 0, 1, 0, 0]]
Traceback (most recent call last):
File "test.py", line 5, in <module>
print(f"Item at pos {i}: {possible.pop(i)}")
IndexError: pop index out of range
Explanation:
As I said before, i keeps increasing, but at the same time, you are removing items from possible.
After the first iteration possible is [[0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]].
But during the next (the second) iteration, you are popping the item at index 1, which is [0, 1, 0, 0, 0] - you were probably expecting [0, 0, 0, 0, 1].
During the third iteration, possible only holds two items: [[0, 0, 0, 0, 1], [0, 0, 1, 0, 0]] but you are trying to pop the item at index 2, which is when the pop index out of range error happens.
Why not simple iterate your list and print the items instead of popping them?
possible = [[0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]]
for item in possible:
print(item)
Output:
[0, 0, 0, 1, 0]
[0, 0, 0, 0, 1]
[0, 1, 0, 0, 0]
[0, 0, 1, 0, 0]

How to produce this specific list of lists

I have a bit of a complicated problem. I'm trying to make a function which takes in a list of 0s and 1s and returns a list of lists. It's easiest if I just show an example
input :
[0,0,0,1,0,1]
output :
[[0,0,0,0,0,0,0],[1,0,0,0,1,0,0],[1,0,0,0,1,0,1],[1,0,0,0,0,0,1],[1,0,0,0,0,0,0]]
Another example
input :
[1,0,1]
output :
[[0,0,0,0],[1,1,0,0],[1,0,0,1],[1,1,0,1],[1,0,0,0]]
I have a solution right now, where I first produce all the the combinations and then filters out the ones that are not allowed. But this demands massive amount of memory so I'm looking for a better solution.
def func(input):
A = list(itertools.product(range(2), repeat=int(len(input)+1)))
# Filters out all the lists which have first element equal to 0
# and 1s anywhere else
A = [item for item in A if not (item[0] == 0 \
and sum(item) >= 1 or item[A.index(item)+1] == 1) ]
# Filter out all lists which has 1s at places the input does not have
A = [item for item in action_space if not \
sum(np.bitwise_and(np.bitwise_xor(item[1:], \
self.adj_mat[node.get_node_nr()]),item[1:])) > 0]
return A
You can get a list of the indices to mutate, then use itertools.product to generate all the possible variations.
from itertools import product
def func(l):
indicies = [i for i, x in enumerate(l, start=1) if x]
prod = product([0, 1], repeat=len(indicies))
yield [0] * (len(l) + 1)
for variation in prod:
temp = [1, *l]
for index, value in zip(indicies, variation):
temp[index] = value
yield temp
print(list(func([0,0,0,1,0,1])))
# [[0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 0], [1, 0, 0, 0, 1, 0, 1]]
print(list(func([1,0,1])))
# [[0, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 1], [1, 1, 0, 0], [1, 1, 0, 1]]
Idea: Get indices. Then take all subsets of indices to generate sublists to add to result
from itertools import chain, combinations
def powerset(iterable):
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
lst = [0,0,0,1,0,1]
indices = [i for i, x in enumerate(lst) if x == 1]
result = [[0] * (len(lst)+1)]
for element in powerset(s):
new_element = [[0] * (len(lst)+1)]
new_element[0][0] = 1
for pos in element:
new_element[0][pos+1] = int(1)
result.extend(new_element)
print(result) # [[0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 1, 0, 0], [1, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 1]]
Use itertools.permutations, and just prepend a 1 to each of them.
from itertools import permutations
def augment(xs):
yield [0] + [0 for _ in xs]
for x in permutations(xs):
yield [1] + list(x)
out = list(augment([1,0,1])
If you'd rather write a single expression rather than a generator function, its just
from itertools import chain, permutations
xs = [1, 0, 1]
out = list(chain([[0] + [0 for _ in xs]], ([1] + list(x) for x in permutations(xs))))
Using itertools.product and a generator:
def get_combinations(lst):
yield [0]*(len(lst)+1)
idxs = [idx for idx, x in enumerate(lst) if x]
for vals in product(*[[0, 1]]*2):
vals_i = iter(vals)
yield [1] + [0 if idx not in idxs else next(vals_i) for idx in range(len(lst))]
Then list(get_combinations([0, 0, 0, 1, 0, 1])) prints
[[0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 1, 0, 1]]

How to construct matrix based on condition and position?

I have a matrix A=
np.matrix([[0, 0, 0, 0, 0],
[0, 0, 0, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 1, 1]]
I wanna build a matrix B where B[i,j]=5 if A[i,j]=1 and (i+1)%3=0; B[i,j]=0 otherwise.
The B should be: B=
np.matrix([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 5, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 5, 0, 0]]
Is there any possible method to achieve this without using for loop, just like matrix calculation? Thank you.
UPDATED ANSWER:
I have not thought of a way to eliminate the for-loop in the list comprehension for filtering on the remainder condition, but the "heavy" part of the computation exploits numpy's optimizations.
import numpy as np
newdata = 5 * np.array([(i + 1) % 3 == 0 for i in range(data.shape[-1])]) * np.array(data)
ORIGINAL ANSWER (prior to condition that for-loops cannot be used):
Assuming your matrix is stored as data, then you can use list comprehension syntax to get what you want.
newdata = [[5 if val == 1 and (idx + 1) % 3 == 0 else 0
for idx, val in enumerate(row)]
for row in data]

Making a line in a matrix go up (Python) - issue with Append that replace instead of Appending item

I want to make an "animation" of an element of matrix going from the bottom line to the top ligne of the matrix.
I have the following code, but something not wanted is ongoing with append function :
import time
#size of the matrix
PixelCarac=4
#List that cointain all the matrixs
ListMatrix=[]
#matrix filled with 0
tempo =[[0 for x in range(PixelCarac)] for y in range(PixelCarac)]
#last line have a difference
tempo[3][0]=1
print("First step")
print(tempo)
#making the line going up.
for x in range(0,PixelCarac-1,1):
#append in the list
ListMatrix.append(tempo)
#display
print("length of the list is " + str(len(ListMatrix)))
for elem in ListMatrix:
print(elem)
#Making the line going up by recopie from 1 line to the upper one
for i in range(0,len(tempo)-1,1):
tempo[i]=tempo[i+1]
time.sleep(20)
the ouput I have is :
First step
[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]
length of the list is 1
[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]
length of the list is 2
[[0,0,0,0],[0,0,0,0],[0,0,0,1],[0,0,0,1]
[[0,0,0,0],[0,0,0,0],[0,0,0,1],[0,0,0,1]
length of the list is 2
[[0,0,0,0],[0,0,0,1],[0,0,0,1],[0,0,0,1]
[[0,0,0,0],[0,0,0,1],[0,0,0,1],[0,0,0,1]
[[0,0,0,0],[0,0,0,1],[0,0,0,1],[0,0,0,1]
the ouput I want is :
First step
[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]
length of the list is 1
[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]
length of the list is 2
[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]
[[0,0,0,0],[0,0,0,0],[0,0,0,1],[0,0,0,1]
length of the list is 2
[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]
[[0,0,0,0],[0,0,0,0],[0,0,0,1],[0,0,0,1]
[[0,0,0,0],[0,0,0,1],[0,0,0,1],[0,0,0,1]
Question :
Why the append function is changing the previous items in the list?
Without knowing exactly what you want, this might be a direction:
import time
#size of the matrix
PixelCarac=4
#List that cointain all the matrixs
ListMatrix=[]
#matrix filled with 0
tempo =[[0 for x in range(PixelCarac)] for y in range(PixelCarac)]
#last line have a difference
tempo[3][3]=1
print("First step")
print(tempo)
#making the line going up.
for x in range(0,PixelCarac-1,1):
#append in the list
ListMatrix.append(tempo)
#display
print("length of the list is " + str(len(ListMatrix)))
for elem in ListMatrix:
print(elem)
#Making the line going up by recopie from 1 line to the upper one
#for i in range(0,len(tempo)-1,1):
# tempo[i]=tempo[i+1]
tempo = tempo[1:]+[tempo[3]]
time.sleep(20)
Gives:
First step
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]
length of the list is 1
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]
length of the list is 2
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1]]
length of the list is 3
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1]]
[[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1]]

python: help in calculation a proportion of 1's in binary sequence

I am writing a program in python. It randomly generates binary strings of length 10 for host and length 7 for parasites. What i need to do now is find the proportion of 1's in each parasite genome and total proportion of 1's in the entire parasite population
import random
host_genome_length = 10
parasite_genome_length = 5
host_initial_population=15
parasite_initial_population=10
assert parasite_initial_population >=0
parasite_initial_chance_1= 0.2
host_initial_chance_1=0.5
hosts=[]
for i in range(host_initial_population):
genome= []
for j in range (host_genome_length):
if random.random()< host_initial_chance_1:
genome.append(1)
else:
genome.append(0)
hosts.append(genome)
print "hosts:"
print hosts
parasites=[]
for i in range(parasite_initial_population):
genome= []
for j in range (parasite_genome_length):
if random.random()< parasite_initial_chance_1:
genome.append(1)
else:
genome.append(0)
parasites.append(genome)
for i in range(host_initial_population-parasite_initial_population):
parasites.append(None)
print "parasites:"
print parasites
for example if the output is [1, 0, 0, 1, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 0, 1, 0, 0], [1, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], None, None, None, None, None]
i need proportion of 1's in each sequence
and total proportion of 1 in the entire list?
If you get only one result at a time, you can do it like this:
res = [1,0,0,1,1]
proportion = float(res.count(1))/len(res)
If the results are all returned as a list of lists:
res = [[1, 0, 0, 1, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 0, 1, 0, 0], [1, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], None, None, None, None, None]
total = sum([ x.count(1) for x in res if x<> None ]) # ignore the None elements
length = sum([len(x) for x in res if x <> None])
proportion = float(total)/length
#pairs of (oneCount, oneProportion)
def prepare(listList):
result = []
for subList in listList:
sLUnitCount = subList.__len__()
slOneCount = sum(subList)
result.append((slOneCount, float(slOneCount)/sLUnitCount))
return result
#individual proportions
def indivProp(listList):
indiv = prepare(listList)
return map(lambda x:x[1])
#total proportions
def totalProp(listList):
indiv = prepare(listList)
slOnesCounts = map(lambda x:x[0],indiv)
totalOnes = sum(slOnesCounts)
slUnitCounts = map(lambda x:x[0]/x[1], indiv)
totalUnits = sum(slUnitCounts)
return totalOnes/totalUnits

Categories