How to use a step outside the range() function - python

I'm working on this code :
Alright = []
for i in range(0, 384, 48):
Alright.append(i)
Alright2 = []
Alright3 = []
for j in range(len(Alright)):
if j % 2 == 0:
Alright2 = (Alright[j], Alright[j+1])
Alright3.append(Alright2)
print(Alright3)
Out : [(0, 48), (96, 144), (192, 240), (288, 336)]
That's Good i wanted those ranges. Now what i want to do is the same thing but for ranges that are not in the past one (Alright3) and get a list with ranges that are not in Alright3, so the output must be like shown in the next step (Wanted Out). Here is my code :
Alright4 = []
for i in range(49, 384, 46):
Alright4.append(i)
Alright5 = []
Alright6 = []
for j in range(len(Alright4)):
if j % 2 == 0:
Alright5 = (Alright4[j], Alright4[j+1])
Alright6.append(Alright5)
print(Alright6)
Out : [(49, 95), (141, 187), (233, 279), (325, 371)]
I want to have this out :
Wanted Out : [(49, 95), (145, 191), (241, 287), (337, 384)]

First, let's refactor your initial code a bit:
Alright = list(range(0, 384, 48))
Alright3 = []
for j in range(0, len(Alright), 2):
Alright2 = (Alright[j], Alright[j+1])
Alright3.append(Alright2)
Now I understand what you're trying to do. I would write it as follows:
ranges = [(i, i + 48) for i in range(0, 384, 48 * 2)]
So because we're going to skip every other entry anyway, why not make the original range with a step twice as large? We also know the second value of each tuple has to be 48 more than the first value of that tuple.
This has the advantage we can use that same method to find the complement:
other_ranges = [(i, i + 46) for i in range(49, 384, 48 * 2)]
Note that the step is the same, but the second element of each tuple is only 46 more than the first.
The only issue is that the last value is 383 rather than 384 as you specified. I believe this is probably going to be the right value, but it's possible to correct afterwards if you really do need 384:
first_value, second_value = other_ranges[-1]
other_ranges[-1] = first_value, second_value + 1

I think it would be a little overcomplicated run a new loops. Just try adjusting your first method like this:
Alright = []
for i in range(0, 384, 48):
Alright.append(i)
Alright2 = []
Alright3 = []
Alright4 = [] #numbers not in Alright3
last = None #saves the higher value of the last added tuple
for j in range(len(Alright)):
if j % 2 == 0:
if last != None: #made to skip the first iteration
Alright4.append((last+1, Alright[j]-1)) #saves the range between the last added tuple and the one being added in this iteration
Alright2 = (Alright[j], Alright[j+1])
Alright3.append(Alright2)
last = Alright[j+1] #saves the higher value of the last added tuple
if last != 384:
Alright4.append((last+1, 384))
print(Alright4)
The contents of Alright4 will look like this:
Out : [(49, 95), (145, 191), (241, 287), (337, 384)]

Alright4 = []
mul = 4
for i in range(49, 384, 46):
Alright4.append(i)
print(Alright4)
Alright5 = []
Alright6 = []
for j in range(len(Alright4)):
if j % 2 == 0:
if j == 0:
Alright5 = (Alright4[j], Alright4[j+1])
Alright6.append(Alright5)
else:
if j == len(Alright4)-2:
mul += 1
Alright5 = (Alright4[j]+mul, Alright4[j+1]+mul)
Alright6.append(Alright5)
mul += 4
print(Alright6)

Related

How to call a function on list to return incremental bits range

I am trying to write a function that returns from and to bits in [from:to] format.
I am not quite sure how exactly it can be done (recursively?). The expected output is in incremental range of bits. Here is the piece of code to start with,
cntlist = [5,1,4,3,1]
def find_size(cnt):
if cnt>1:
a = "[%s:%s]" % (cnt-1, cnt-cnt)
left = cnt-1
right = cnt-cnt
if cnt==1:
a = "[%s]" % (cnt)
left = a
right = a
return a, left, right
newlist = list(map(find_size, cntlist))
print(newlist)
Output:
[('[4:0]', 4, 0), ('[1]', '[1]', '[1]'), ('[3:0]', 3, 0), ('[2:0]', 2, 0), ('[1]', '[1]', '[1]')]
Expected output:
['[4:0]', '[5]', '[9:6]', '[12:10]', '[13]']
Note: If size is 1 in cntlist, the range will have only one element which will be +1 to previous range's left number.
IIUC, a simple loop should work:
def bitrange(cntlst):
out = []
total = 0
for i in cntlst:
prev = total
total += i
if i == 1:
out.append(f'[{total-1}]')
else:
out.append(f'[{total-1}:{prev}]')
return out
bitrange([5,1,4,3,1])
output:
['[4:0]', '[5]', '[9:6]', '[12:10]', '[13]']

How can I make a multiple for loop with each value getting in one at a time?

T_list = []
Temp_k = np.linspace(298, 398, 10)
#print (Temp_k)
current = np.linspace(0, 1.4, 5)
ppH2O = np.linspace(-2, -1, 5)
H2_pressure = []
H2O_pp = ppH2O
for i in (Temp_k):
print(i, 'i')
for j in (H2O_pp):
print(j, 'j')
for k in (current):
print (k, 'k')
partial_H2 = 5*np.exp((1.653 * k)/i) - 1/j
H2_pressure.append(partial_H2)
#print (H2_pressure)
I want to make a list of an array that gives me the values of
5*np.exp((1.653 * k)/i) - 1/j,
At each Temp_k, H2O_pp, current.
For example, value of when Temp_k , H2O_pp and current is at their initial value,
value at their second value, .... till it reaches to the end values.
Could someone please help me with this?
What about this
import numpy as np
temp_k = np.linspace(298, 398, 10)
pp_h2o = np.linspace(-2, -1, 5)
currents = np.linspace(0, 1.4, 5)
h2_pressures = []
for temp in temp_k:
for pp in pp_h2o:
for current in currents:
h2_pressure = 5 * np.exp((1.653 * current) / temp) - 1 / pp
h2_pressures.append(h2_pressure)
print(f'temp: {temp:0.1f}, pp: {pp:.2f}, current: {current:.3f}, h2_pressure: {h2_pressure:.4f}')
#print(h2_pressures)
Changes:
choose more logical variable names conform Python convention
removed the () around the lists in the for loops
put the h2_pressures.append in the inner for loop
format the print out
Your problem is you put append outside of every loop. You should append what you calculated at the most inner loop, where you calculated it. Otherwise when loop is terminated there is no access to previously calculated values.
T_list = []
Temp_k = np.linspace(298, 398, 10)
#print (Temp_k)
current = np.linspace(0, 1.4, 5)
ppH2O = np.linspace(-2, -1, 5)
H2_pressure = []
H2O_pp = ppH2O
for i in (Temp_k):
print(i, 'i')
for j in (H2O_pp):
print(j, 'j')
for k in (current):
print (k, 'k')
partial_H2 = 5*np.exp((1.653 * k)/i) - 1/j
H2_pressure.append(partial_H2)

dynamic format the string from tuples of tuple using python

In the below, Scenario 1 is working fine in both (Code 1 & Code 2). But Scenario 2 is not working in Code 1.
My requirement is Tuple should keep on repeating itself until it fills all the formatting string in the Query dynamically. Because where clauses are not constant for all the queries.
Scenario 1#
query = SELECT * FROM test.order where total_price in {}
Tuple:
finTup=((125, 125, 125, 125),)
SELECT * FROM test.order where total_price in (125, 125, 125, 125)
Scenario 2#
query = SELECT * FROM test.order WHERE order_id IN {} AND product_id IN {}
Tuple:
finTup=((101, 105, 106, 107), (2, 2, 2, 2))
Code 1:
frt = 'finTup[{}]'
half = ''
val = ''
i = 0
le = len(finTup)
for i in range(le):
print(i)
print(eval(frt.format(i)))
if i == le -1:
half = half + frt.format(i)
val = val + " " + frt.format(i)
else:
half = half + frt.format(i)+', '
val = val + " " + frt.format(i)+', '
temp2 = query.format(eval(val))
Code 2:
if le == 1:
query = query.format(finTup[0])
elif le == 2:
query = query.format(finTup[0], finTup[1])
elif le == 3:
query = query.format(finTup[0], finTup[1], finTup[2])
elif le == 4:
query = query.format(finTup[0], finTup[1], finTup[2], finTup[3])
Error:
temp2 = query.format(eval(val))
IndexError: tuple index out of range
Please help me to fix this.
TL;DR
Hello, you have this error because you are trying to provide a single argument to the format function which expects two parameters (since you have 2 {}).
Note: Avoid using the eval function... That's pretty not recommended, even less in the current situation that you are. Everything can be done without having to evaluate a str.
In what follows, I only run the code for Scenario #2, i.e.
query2 = """SELECT * FROM test.order WHERE order_id IN {} AND product_id IN {}"""
finTup = ((101, 105, 106, 107), (2, 2, 2, 2))
Step 1: Debugging
Let's imagine you update your code for debugging as follows:
frt = 'finTup[{}]'
half = ''
val = ''
i = 0 # btw, you don't need to initialize i here
le = len(finTup)
for i in range(le):
if i == le -1:
half = half + frt.format(i)
val = val + " " + frt.format(i)
else:
half = half + frt.format(i)+', '
val = val + " " + frt.format(i)+', '
print val
print eval(val)
temp2 = query.format(eval(val))
Your output should be:
vars[0], vars[1]
((101, 105, 106, 107), (2, 2, 2, 2))
So, imagine you write python code from the above output, what you would do is:
query.format(((101, 105, 106, 107), (2, 2, 2, 2)))
You are actually providing a single parameter of type tuple with a two elements. But what's important here is that you provide format with a single parameter. The format function will try to access the second parameter, which you don't provide. It breaks.
Step 2: Fixing the code
Have a look at this SO article. It shows you how to use the * operator. It basically transforms a list or tuple into a sequence of items. Perfect for functions parameters and so forth.
So, applied to your current case:
temp2 = query.format(*eval(val))
And the trick is done.
Step 3: Optimization
Now, let's trash the Code 1 and use what we've learn with Code 2. We need to unpack the tuple of tuple into parameters to feed in to format. So, why not just do:
# I renamed `finTup` to `vars` since I don't know what it means
def get_query(query, vars):
return query.format(*vars)
It basically combines the logic of Code 1 and Code 2 into a single line.

How to exclude a range from another range in Python?

Suppose I've a range (section) and an additional list of ranges to exclude, represented by tuples (start, end):
section=(1, 100) #Range from 1 to 100
toexclude=[(10,15),(40,50),(80,83)] #3 sub-ranges
I'm looking for an efficient algorithm which returns, from these two inputs, a new list of ranges like:
[(1,9),(16,39),(51,79),(84,100)]
Which is the main range exluding the second list of ranges.
Thanks!
EDIT:
Actually the advice from deceze to use intervaltree seems to be interesting. With a few lines:
from intervaltree import Interval, IntervalTree
t=IntervalTree()
t[1:100]="main"
t.chop(10,15)
t.chop(40,50)
t.chop(80,83)
t
IntervalTree([Interval(1, 10, 'main'), Interval(15, 40, 'main'), Interval(50, 80, 'main'), Interval(83, 100, 'main')])
The intervals are considered closed apparently, but this is a minor issue.
section=(1, 100) #Range from 1 to 100
toexclude=[(10,15),(40,50),(80,83)] #3 sub-ranges
rangelists = [x for excRange in toexclude for x in range(excRange[0], excRange[1] + 1)]
first, last = section[0], section[0]
out_ranges = []
for x in range(section[0],section[1] + 1):
if x not in rangelists:
if first == 'unset':
first = x
last = x
elif x in rangelists:
if last == x - 1:
out_ranges.append((first, last))
first = 'unset'
else:
continue
if first != 'unset':
out_ranges.append((first, last))
print out_ranges
Somethink like this?
start, end = section
this_start = start
result = []
for exc_start, exc_end in toexclude:
this_end = exc_start - 1
result.append((this_start, this_end))
this_start = exc_end + 1
result.append((this_start, end))
EDIT: added if clause to correct according to Paco H. comment
start, end = section
this_start = start
result = []
for exc_start, exc_end in toexclude:
if this_end == start:
start = exc_end + 1
else:
this_end = exc_start - 1
result.append((this_start, this_end))
this_start = exc_end + 1
if this_end <= end:
result.append((this_start, end))
section=(1, 100) #Range from 1 to 100
toexclude=[(10,15),(40,50),(80,83)] #3 sub-rang
list1 = []
list2 = [section[0]]
[list1.append(x[0]-1) for x in toexclude]
[list2.append(x[1]+1) for x in toexclude]
list1.append(section[1])
print list(zip(list2, list1)
# [(1, 9), (16, 39), (51, 79), (84, 100)]

How do I make sure that my sliding window is creating the right amount of windows?

Thanks! I modified my sliding window code code from here, but it stills creates one less window than there should be.
If you want more info on the problem, I wrote about the initial problem there. In short, I am dealing with a large text file containing the decimal places of pi that has this format. Note that the header is all numbers and does not have a string.
I need to make a sliding window that crops the file using three arguments (window_size, step_size, and last_windowstart). last_windowstart is where the last window starts.
It works but there should be 238 windows not 237.
I know lastcounter is working right, but I'm not sure about lastwindow_start. I have tried changing its value and it is definitely part of the problem.
Xrange has to be part of the problem too
Any thoughts on sliding_window or lastwindow_start?
inputFileName = "sample.txt"
import itertools
import linecache
def sliding_window(window_size, step_size, lastwindow_start):
for i in xrange(0, lastwindow_start, step_size):
yield (i, i + window_size)
def PiCrop(window_size, step_size):
f = open(inputFileName, 'r')
first_line = f.readline().split()
Total_Pi_Digits = int(first_line[0])
lastwindow_start = Total_Pi_Digits-(Total_Pi_Digits%window_size)
lastcounter = (Total_Pi_Digits//window_size)*(window_size/step_size)
flags = [False for i in range(lastcounter)]
first_line[0] = str(window_size)
second_line = f.readline().split()
offset = int(round(float(second_line[0].strip('\n'))))
first_line = " ".join(first_line)
f. close()
with open(inputFileName, 'r') as f:
header = f.readline()
data = [line.strip().split(',') for line in f.readlines()]
for counter, window in enumerate(sliding_window(window_size,step_size,lastwindow_start)):
chunk = data[window[0]:window[1]]
with open('PiCrop_{}.txt'.format(counter), 'w') as output:
if (flags[counter] == False):
flags[counter] = True
headerline = float(linecache.getline(inputFileName, window[1]+1)) - offset
output.write(str(window_size) + " " + str("{0:.4f}".format(headerline)) + " " + 'L' + '\n')
for item in chunk:
newline = str("{0:.4f}".format(float(str(item).translate(None, "[]'"))-offset))
output.write(str(newline) + '\n')
PiCrop(1000,500)
You have to add an exception to handle the remainder.
Say you have 99 pi_digits and you want 10 pi_digits in each file (window_size). But since there are 99 pi_digits, there can't be 10 pi_digits in each window.
There will be 10 pi_digits in the first 9 windows and 9 pi_digits in the last window.
This gives us a total of 10 windows with a step_size of 0.
Since there isn't a step_size, we need to factor that into the program.
Let's use a step_size of 5. This moves up the pair by 5 each time
The pairs are as following:
(0, 10)
(5, 15)
(10, 20)
(15, 25)
(20, 30)
(25, 35)
(30, 40)
(35, 45)
(40, 50)
(45, 55)
(50, 60)
(55, 65)
(60, 70)
(65, 75)
(70, 80)
(75, 85)
(80, 90)
(85, 95)
(90,99)
Note the last pair is (90,99). This breaks the pattern.
So we add the following line 'yield (lastwindow_start, total_pi_digits)' to add the last pair, whi
def sliding_window(window_size, step_size, lastwindow_start,total_pi_digits):
for i in xrange(0, lastwindow_start, step_size):
yield (i, i + window_size)
yield (lastwindow_start, total_pi_digits)

Categories