how to make a iterable object like this? - python

Question 1
how to make an iterable object like this:
0 1 2 3 4 5 4 3 2 1 0 1 2 3 4 5 4 3 2 1 0 1 2 3 4 5 4 3 2 1 ....
Question 2
if use list(obj) on the object above would this eat up machine's memory? how to prevent it?
Please don't use python2

You can make an infinite generator that counts up and down:
def updown(n):
while True:
for i in range(n):
yield i
for i in range(n - 2, 0, -1):
yield i
uptofive = updown(6)
for i in range(20):
print uptofive.next(),
would output:
0 1 2 3 4 5 4 3 2 1 0 1 2 3 4 5 4 3 2 1
You cannot prevent list(updown(6)) from trying to consume all memory, no. As the doctor would say: "Then don't do that!".
Use .next() calls instead, or use your generator with another statement that limits the number of times you iterate over the generator. The itertools.islice() function would do just that:
import itertools
list(itertools.islice(updown(6), 20))

An alternative is to use itertools.cycle():
from itertools import cycle
def oscillator(start, stop):
# assumes stop >= start
return cycle(range(start, stop+1) + range(stop-1, start, -1))
o = oscillator(0, 5)
for i in range(30):
print o.next(),

Related

Skip particular repetition in nested foor loop - Python

for k in range(8):
for i in range(2): #number of columns
for j in range(4): #number of row
print(k,j,i)
I want an output like this. no repetition of first for loop
k,j,i
-----
0 0 0
1 1 0
2 2 0
3 3 0
4 0 1
5 1 1
6 2 1
7 3 1
How I will achieve this?
Normally i would do
for i in range(8):
print(i, i%4, i%2)
Output:
0 0 0
1 1 1
2 2 0
3 3 1
4 0 0
5 1 1
6 2 0
7 3 1
But to reproduce your exact output:
for i in range(8):
print(i, i%4, int(i>3))
Output:
0 0 0
1 1 0
2 2 0
3 3 0
4 0 0
5 1 1
6 2 1
7 3 1
You can use if statements to say things like if k == 7 or something along those lines. This will only allow it to loop the first loop before moving on to the second loop.
Other answers have shown similar ways to produce your exact output, but this is another way to do it, and this would still work if you wanted the number of rows to be more than 8 and you wanted i to keep increasing
for i in range(8):
print(i, i%4, i//4)
I hope this is useful, sorry if it isn't
Looking at i and j, you have the cartesian product of {0,1} and {0,1,2,3}. You can compute that with itertools.product(range(2), range(4)), then use enumerate to number them for your k value.
from itertools import product
for k, (i, j) in enumerate(product(range(2), range(4))):
print(k, j, i)
Earlier arguments to product vary more slowly than later arguments.

Is there a way to reference a previous value in Pandas column efficiently?

I want to do some complex calculations in pandas while referencing previous values (basically I'm calculating row by row). However the loops take forever and I wanted to know if there was a faster way. Everybody keeps mentioning using shift but I don't understand how that would even work.
df = pd.DataFrame(index=range(500)
df["A"]= 2
df["B"]= 5
df["A"][0]= 1
for i in range(len(df):
if i != 0: df['A'][i] = (df['A'][i-1] / 3) - df['B'][i-1] + 25
numpy_ext can be used for expanding calculations
pandas-rolling-apply-using-multiple-columns for reference
I have also included a simpler calc to demonstrate behaviour in simpler way
df = pd.DataFrame(index=range(5000))
df["A"]= 2
df["B"]= 5
df["A"][0]= 1
import numpy_ext as npe
# for i in range(len(df):
# if i != 0: df['A'][i] = (df['A'][i-1] / 3) - df['B'][i-1] + 25
# SO example - function of previous values in A and B
def f(A,B):
r = np.sum(A[:-1]/3) - np.sum(B[:-1] + 25) if len(A)>1 else A[0]
return r
# much simpler example, sum of previous values
def g(A):
return np.sum(A[:-1])
df["AB_combo"] = npe.expanding_apply(f, 1, df["A"].values, df["B"].values)
df["A_running"] = npe.expanding_apply(g, 1, df["A"].values)
print(df.head(10).to_markdown())
sample output
A
B
AB_combo
A_running
0
1
5
1
0
1
2
5
-29.6667
1
2
2
5
-59
3
3
2
5
-88.3333
5
4
2
5
-117.667
7
5
2
5
-147
9
6
2
5
-176.333
11
7
2
5
-205.667
13
8
2
5
-235
15
9
2
5
-264.333
17

Why does this Python nested for loop produce the output I get?

I'm very new to learning python, though I understand the basics of the looping, I am unable to understand the method in which output is arrived at.
In particular, how does the mapping of all three for loops happen to give the desired output, as I finding it impossible to understand the logic to be applied, when I try to write the output on paper without referring to IDE.
Code:
n = 4
a = 3
z = 2
for i in range(n):
for j in range(a):
for p in range(z):
print(i, j, p)
Output is:
0 0 0
0 0 1
0 1 0
0 1 1
0 2 0
0 2 1
1 0 0
1 0 1
1 1 0
1 1 1
1 2 0
1 2 1
2 0 0
2 0 1
2 1 0
2 1 1
2 2 0
2 2 1
3 0 0
3 0 1
3 1 0
3 1 1
3 2 0
3 2 1
The first loop iterates four times.
The second loop iterates three times. However since it is embedded inside the first loop, it actually iterates twelve times (4 * 3.)
The third loop iterates two times. However since it is embedded inside the first and second loops, it actually iterates twenty-four times (4 * 3 * 2).

Dynamic For Loops in Python

i understand that to create dynamic for loops, recursive or itertools module in python is the way to go. Lets say I am doing it in recursive.
What I want is
for var1 in range(var1_lowerlimit, var1_upperlimit, var1_stepsize):
for var2 in range(var2_lowerlimit, var2_upperlimit, var2_stepsize):
:
:
# do_whatever()
repeat for n loops where n is the number of variables
What I have now is I have 2 lists
variable_list = [ var1, var2, var3, ... ]
boundaries_list = [ [var1_lowerlimit, var1_upperlimit, var1_stepsize],
[var2_lowerlimit, var2_upperlimit, var2_stepsize], ...]
def dynamic_for_loop(variable_list , boundaries_list, no_of_loops, list_index = 0):
if no_of_loops <= 0:
# do_whatever()
else:
lower_bound = boundaries_list[list_index][0]
upper_bound = boundaries_list[list_index][1]
step_size = boundaries_list[list_index][2]
for index in range(lower_bound, upper_bound, step_size):
list_index += 1
try:
dynamic_for_loop(variable_list , boundaries_list, no_of_loops - 1, list_index)
except:
list_index = 0
dynamic_for_loop(variable_list , boundaries_list, no_of_loops - 1, list_index)
I did a reset on list_index as it gets out of range, but i couldn't get the result I want. Can someone enlighten me what went wrong?
Use the itertools.product() function to generate the values over a variable number of ranges:
for values in product(*(range(*b) for b in boundaries_list)):
# do things with the values tuple, do_whatever(*values) perhaps
Don't try to set a variable number of variables; just iterate over the values tuple or use indexing as needed.
Using * in a call tells Python to take all elements of an iterable and apply them as separate arguments. So each b in your boundaries_list is applied to range() as separate arguments, as if you called range(b[0], b[1], b[2]).
The same applies to the product() call; each range() object the generator expression produces is passed to product() as a separate argument. This way you can pass a dynamic number of range() objects to that call.
Just for fun, I thought that I would implement this using recursion to perhaps demonstrate the pythonic style. Of course, the most pythonic way would be to use the itertools package as demonstrated by Martijn Pieters.
def dynamic_for_loop(boundaries, *vargs):
if not boundaries:
print(*vargs) # or whatever you want to do with the values
else:
bounds = boundaries[0]
for i in range(*bounds):
dynamic_for_loop(boundaries[1:], *(vargs + (i,)))
Now we can use it like so:
In [2]: boundaries = [[0,5,1], [0,3,1], [0,3,1]]
In [3]: dynamic_for_loop(boundaries)
0 0 0
0 0 1
0 0 2
0 1 0
0 1 1
0 1 2
0 2 0
0 2 1
0 2 2
1 0 0
1 0 1
1 0 2
1 1 0
1 1 1
1 1 2
1 2 0
1 2 1
1 2 2
2 0 0
2 0 1
2 0 2
2 1 0
2 1 1
2 1 2
2 2 0
2 2 1
2 2 2
3 0 0
3 0 1
3 0 2
3 1 0
3 1 1
3 1 2
3 2 0
3 2 1
3 2 2
4 0 0
4 0 1
4 0 2
4 1 0
4 1 1
4 1 2
4 2 0
4 2 1
4 2 2

Python: Two Nested Loops

I'm trying to find coding for Python version 3 doing these two things in basic coding (a loop nested inside another loop). I understand the basic premise of:
for i in range(10)
for j in range(10)
but I think it's the "i+___" math that's giving me trouble. I'm having trouble giving me these three types of outputs:
First:
0
0 1
0 1 2
0 1 2 3
Second:
10
11 12
13 14 15
16 17 18 19
Third:
0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2
Any help would be greatly appreciated.
For python version 3.
First:
for i in range(4):
for j in range(i+1):
print(j, end="")
print()
Second:
x=10
for i in range(1,5):
for j in range(x,i+x):
print(str(j)+" ", end="")
x+=i
print()
Third:
for i in range(3):
print((str(i)+" ")*9)
Third:
j=[]
for i in xrange(0,3):
j.append([i]*9)

Categories

Resources