Cycle through a variable range with another variable - python-3.x

I need to loop through 2 variables and cycle through 1 variable from 2 variables (whichever is bigger) until the range of the 2nd (longest) last.
For example
x = 5 #input by user
y = 8 #input by user
for x_val, y_val in itertools.zip_longest(range(x), range(y), fillvalue='-'):
print(x_val)
print(y_val)
Expected output
0
0
1
1
2
2
3
3
4
4
0
5
1
6
2
7
tried
x = 5
x_cyc = itertools.cycle(range(x))
y = 8
for x_val, y_val in itertools.zip_longest(range(x), x_cyc):
print(x_val)
print(y_val)
but that didn't make much sense.

you dont need zip longest, you create an infinite cycle for the smaller of the two numbers and then normal range for the larger number. this way the min range will be infinite and max range will be the finite range.
You can simply use normal zip to go through them till you reach the end of the non infinite range.
from itertools import cycle
x = 8
y = 5
min_range = cycle(range(min(x, y)))
max_range = range(max(x, y))
for x_val, y_val in zip(min_range, max_range):
print(x_val)
print(y_val)
OUTPUT
0
0
1
1
2
2
3
3
4
4
0
5
1
6
2
7
UPDATE BASED ON COMMENTS
Now the x_val and y_val are bound to the x and y range and the lowest of x or y ints will be cycled in range.
from itertools import cycle
x = 8
y = 5
x_range = range(x)
y_range = range(y)
if x > y:
y_range = cycle(y_range)
elif y > x:
x_range = cycle(x_range)
for x_val, y_val in zip(x_range, y_range):
print(x_val)
print(y_val)
Note that the output will now differ when x is greater than y or when y is greater than x since x will always output first.
OUTPUT x=2, y=3
0
0
1
1
0
2
OUTPUT x=3 y=2
0
0
1
1
2
0

Related

Compare current value with n values above and below on Pandas DataFrame

I have this df:
x
0 2
1 2
2 2
3 1
4 1
5 2
6 2
I need to compare current value on column x with respect to the n previous and next values based on a defined condition, if condition is met q times then add 1 in a new column, if not, add 0.
For instance, if n is 2, q is 3 and the condition is current_value <= value / 2. In this case, the code will do 7 comparisons:
1st comparison: compare current_value = 2 to previous n = 2 numbers (in this case there are no such numbers because is the first value on the column) and then compare current_value = 2 to the next n = 2 values (in this case both numbers are 2, so condtion is not met on neither (2 <= 2/2)). In this case there are no conditions met, as q = 3 >= 0 the code adds 0 to the new column.
2nd comparison: compare current_value = 2 to previous n = 2 numbers (in this case there is just one number above, the condition is not met (2 <= 2/2)) and then compare current_value = 2 to the next n = 2 values (in this case there's a number 2 and then a number 1, so condition is not met (2 <= 2/2 and 2 <= 1/2)). In this case there are no conditions met, as q = 3 >= 0 the code adds 0 to the new column.
3rd comparison: In this case there are no condition met, as q = 3 >= 0 the code adds 0 to the new column.
4th comparison: compare current_value = 1 to previous n = 2 numbers (in this case there are two number 2 above, the condition is met on both of them (1 <= 2/2)) and then compare current_value = 1 to the next n = 2 values (in this case there's a number 1 and then a number 2, so condition is met once (1 <= 2/2 and 1 <= 1/2)). In this case there are 3 conditions met, as q = 3 >= 3 the code adds 1 to the new column.
5th comparison: In this case there are 3 conditions met, as q = 3 >= 3 the code adds 1 to the new column.
6th comparison: In this case there are no conditions met, as q = 3 >= 0 the code adds 0 to the new column.
7th comparison: In this case there are no conditions met, as q = 3 >= 0 the code adds 0 to the new column.
Desired result:
x comparison
0 2 0
1 2 0
2 2 0
3 1 1
4 1 1
5 2 0
6 2 0
I was thinking on using something like shift function but I'm not sure how to implement it. Any help?
I suggest to use numpy here, to benefit from its sliding window view:
import numpy as np
from numpy.lib.stride_tricks import sliding_window_view as swv
n = 2
q = 3
# convert to numpy array
a = df['x'].astype(float).to_numpy()
# create a sliding window
# remove central value, divide by 2
# compare to original value
# count number of matches
count = (a[:,None] <= swv(np.pad(a, n, constant_values=np.nan), 2*n+1)[:, np.r_[:n,n+1:2*n+1]]/2).sum(1)
# array([0, 0, 0, 3, 3, 0, 0])
# compare number of matches to q
df['comparison'] = (count >= q).astype(int)
print(df)
An alternative with only pandas would require to compute two rolling windows (forward and backward) as it's not trivial to access the current index in a centered rolling with min_periods=1:
n = 2
q = 3
s1 = df['x'].rolling(n+1, min_periods=2).apply(lambda x: sum(x.iloc[-1]<=x.iloc[:-1]/2))
s2 = df.loc[::-1, 'x'].rolling(n+1, min_periods=2).apply(lambda x: sum(x.iloc[-1]<=x.iloc[:-1]/2))
df['comparison'] = s1.add(s2, fill_value=0).ge(3).astype(int)
Output:
x comparison
0 2 0
1 2 0
2 2 0
3 1 1
4 1 1
5 2 0
6 2 0

Populate cells based on x by y cell value

I'm trying to populate cells based on values from two different cells.
Values in the cell needs to be (n-1) where n is the input and then repeated based on the amount of the other cell.
For example, I have input:
x y
2 5
Output should be:
x should have 0 and 1; each repeated five times
y should have 0, 1, 2, 3, 4; each repeated twice
x1 y1
0 0
0 1
0 2
0 3
0 4
1 0
1 1
1 2
1 3
1 4
I used:
=IF(ROW()<=C2+1,K2-1,"")
and
=IF(ROW()<=d2+1,K2-1,"")
but it is not repeating and I only see:
x y
0 0
1 1
__ 2
__ 3
__ 4
(C2 and D2 are where values for x and y are, K is the number of items.)
Are there any suggestions on how I can do this?
In Row2 and copied down to suit:
=IF(ROW()<=1+C$2*D$2,INT((ROW()-2)/D$2),"")
and
=IF(ROW()<=1+C$2*D$2,MOD(ROW()-2,D$2),"")

Pandas - create column with aggregate results

I have a dataset which has a row for each loan, and a borrower can have multiple loans. The 'Property' flag shows if there is any security behind the loan. I am trying to aggregate this flag on a borrower level, so for each borrower, if one of the Property flags is 'Y', I want to add an additional column where it is 'Y' for each of the borrowers.
The short example below shows what the end result should look like. Any help would be appreciated.
import pandas as pd
data = {'Borrower': [1,2,2,2,3,3,4,5,6,6],
'Loan' : [1,2,3,4,5,6,7,8,9,10],
'Property': ["Y","N","Y","Y","N","Y","N","Y","N","N"],
'Result': ['Y','Y','Y','Y','Y','Y','N','Y','N','N']}
df = pd.DataFrame.from_dict(data)
You can use Transform on Property after groupby Borrower. Because the ASCII code of 'Y' is bigger than 'N' so if there is any property which is 'Y' for a borrower, max(Property) will give 'Y'.
df['Result2'] = df.groupby('Borrower')['Property'].transform(max)
df
Out[202]:
Borrower Loan Property Result Result2
0 1 1 Y Y Y
1 2 2 N Y Y
2 2 3 Y Y Y
3 2 4 Y Y Y
4 3 5 N Y Y
5 3 6 Y Y Y
6 4 7 N N N
7 5 8 Y Y Y
8 6 9 N N N
9 6 10 N N N

Python Modulo Function

I understand that the Modulo function returns the remainder of a division problem.
Ex: 16 % 5 = 3 with a remainder of 1. So 1 would be returned.
>>> 1 % 3 Three goes into 1 zero times remainder 1
1
>>> 2 % 3 Three goes into 2 zero times remainder 2
2
>>> 0 % 3 What happens here? 3 goes into zero, zero times remainder 3
if we follow the logic of the previous two illustrations, that is not what was returned, zero was. Why?
>>> 0 % 3
0
The Python % operator is defined so that x % y == x - (x // y) * y, where x // y = ⌊x / y⌋. For positive integers, this corresponds to the usual notion of the “remainder” of a division. So, for any y ≠ 0,
0 % y
= 0 - ⌊0 / y⌋ * y by definition of %
= 0 - ⌊0⌋ * y because 0 divided by anything is 0
= 0 - 0 * y because 0 is an integer, so floor leaves it unchanged
= 0 - 0 because 0 times anything is 0
= 0
Look at it again:
1 % 3 is 0 remainder 1 => 1 = 3*0 + 1
2 % 3 is 0 remainder 2 => 2 = 3*0 + 2
0 % 3 is 0 remainder 0 [not 3] because 0 = 3*0 + 0
why are you taking what remains after the division in the first two cases but not the last?

How to use nested while loops

I'm trying to make a function that uses a nested while loop that prints something like this.
ranges(5,2)
5
0 1 2 3 4
4
0 1 2 3
3
0 1 2
2
0 1
my code that i have so far looks like this
def ranges(high,low):
while high >= low:
print(high)
high = high - 1
y = 0
x = high
while x > y:
print (y, end = " ")
y = y + 1
The output is like this
5
0 1 2 3 4
0 1 2 3
0 1 2
0
I'm pretty sure I missed up in calling the nested while loop because when i split up the code to just print 5,...,2 in a column it works and so does the code for printing the numbers in a row. Any help would be cool
Add print("") right after the while loop, and modify the condition of the while loop to >=:
def ranges(high,low):
while high >= low: # <-- change the condition otherwise you'll miss the last number in every line
print(high)
high = high - 1
y = 0
x = high
while x >= y:
print (y, end = " ")
y = y + 1
print("") # <-- this
ranges(5, 2)
OUTPUT
5
0 1 2 3 4
4
0 1 2 3
3
0 1 2
2
0 1

Resources