I need to use a string to determine which calculation to run. I am trying to use a dispatch table instead of an elif ladder. I need to run some one liners, some multi-line functions, and I need to run a function based on a portion a an incoming state.
This code is simplified to explain. The first 4 functions work but the last 3 do not.
<!-- language: python -->
Fun = functions.get(reference, lambda : print('Invalid Ref'))
fun(my_df, start, stop)
def Ripple(df, start, stop):#Some multi-line function
temp = df.trc3_s12_db[df.index >= start, df.index <= stop]
return temp.values.max() - temp.values.min()
def RAve(df, start, stop, ave, spacing=100):#Changing function
return df.trc3_s12_db.rolling(ave*spacing).[df.index >= start, df.index <= stop].min()
functions = { #Dispatch Table
'MinA': lambda df, start, stop: df[df.index >= start, df.index <= stop].tA.min() * (-1),
'MaxA': lambda df, start, stop: df[df.index >= start, df.index <= stop].tA.max() * (-1),
'MinB': lambda df, start, stop: df[df.index >= start, df.index <= stop].tB.min() * (-1),
'Ripple': Ripple,
'5MHz Ave': RAve(ave=5),
'2.2MHz Ave': RAve(ave=2.2),
'%dMHz Ave': RAve(ave=%d) #Is this possible?
}
I know I can pass functions and arguments using a tuple but then the whole table needs to be a tuple.
Can I pass variables through the formatting of a string into a dispatch table?
What is the best way to sort through these possibilities?
For the first part, it looks like you're trying to create a partial function, a function made of anotherfunction with some of it's arguments 'burned in'.
For the second part '%dMHz Ave': RAve(ave=%d) #Is this possible? - no, this isn't possible. You'd need some other logic to detect this case, and then use something other than the dispatch table (dict) in that case. E.g. Use a regexp to check if the expression matches "xxxMHz Ave" and in that case to use RAve(ave=xxx)m
Related
In MySQL, If I have a list of date ranges (range-start and range-end). e.g.
10/06/1983 to 14/06/1983
15/07/1983 to 16/07/1983
18/07/1983 to 18/07/1983
And I want to check if another date range contains ANY of the ranges already in the list, how would I do that?
e.g.
06/06/1983 to 18/06/1983 = IN LIST
10/06/1983 to 11/06/1983 = IN LIST
14/07/1983 to 14/07/1983 = NOT IN LIST
This is a classical problem, and it's actually easier if you reverse the logic.
Let me give you an example.
I'll post one period of time here, and all the different variations of other periods that overlap in some way.
|-------------------| compare to this one
|---------| contained within
|----------| contained within, equal start
|-----------| contained within, equal end
|-------------------| contained within, equal start+end
|------------| not fully contained, overlaps start
|---------------| not fully contained, overlaps end
|-------------------------| overlaps start, bigger
|-----------------------| overlaps end, bigger
|------------------------------| overlaps entire period
on the other hand, let me post all those that doesn't overlap:
|-------------------| compare to this one
|---| ends before
|---| starts after
So if you simple reduce the comparison to:
starts after end
ends before start
then you'll find all those that doesn't overlap, and then you'll find all the non-matching periods.
For your final NOT IN LIST example, you can see that it matches those two rules.
You will need to decide wether the following periods are IN or OUTSIDE your ranges:
|-------------|
|-------| equal end with start of comparison period
|-----| equal start with end of comparison period
If your table has columns called range_end and range_start, here's some simple SQL to retrieve all the matching rows:
SELECT *
FROM periods
WHERE NOT (range_start > #check_period_end
OR range_end < #check_period_start)
Note the NOT in there. Since the two simple rules finds all the non-matching rows, a simple NOT will reverse it to say: if it's not one of the non-matching rows, it has to be one of the matching ones.
Applying simple reversal logic here to get rid of the NOT and you'll end up with:
SELECT *
FROM periods
WHERE range_start <= #check_period_end
AND range_end >= #check_period_start
Taking your example range of 06/06/1983 to 18/06/1983 and assuming you have columns called start and end for your ranges, you could use a clause like this
where ('1983-06-06' <= end) and ('1983-06-18' >= start)
i.e. check the start of your test range is before the end of the database range, and that the end of your test range is after or on the start of the database range.
If your RDBMS supports the OVERLAP() function then this becomes trivial -- no need for homegrown solutions. (In Oracle it apparantly works but is undocumented).
In your expected results you say
06/06/1983 to 18/06/1983 = IN LIST
However, this period does not contain nor is contained by any of the periods in your table (not list!) of periods. It does, however, overlap the period 10/06/1983 to 14/06/1983.
You may find the Snodgrass book (http://www.cs.arizona.edu/people/rts/tdbbook.pdf) useful: it pre-dates mysql but the concept of time hasn't changed ;-)
I created function to deal with this problem in MySQL. Just convert the dates to seconds before use.
DELIMITER ;;
CREATE FUNCTION overlap_interval(x INT,y INT,a INT,b INT)
RETURNS INTEGER DETERMINISTIC
BEGIN
DECLARE
overlap_amount INTEGER;
IF (((x <= a) AND (a < y)) OR ((x < b) AND (b <= y)) OR (a < x AND y < b)) THEN
IF (x < a) THEN
IF (y < b) THEN
SET overlap_amount = y - a;
ELSE
SET overlap_amount = b - a;
END IF;
ELSE
IF (y < b) THEN
SET overlap_amount = y - x;
ELSE
SET overlap_amount = b - x;
END IF;
END IF;
ELSE
SET overlap_amount = 0;
END IF;
RETURN overlap_amount;
END ;;
DELIMITER ;
Look into the following example. It will helpful for you.
SELECT DISTINCT RelatedTo,CAST(NotificationContent as nvarchar(max)) as NotificationContent,
ID,
Url,
NotificationPrefix,
NotificationDate
FROM NotificationMaster as nfm
inner join NotificationSettingsSubscriptionLog as nfl on nfm.NotificationDate between nfl.LastSubscribedDate and isnull(nfl.LastUnSubscribedDate,GETDATE())
where ID not in(SELECT NotificationID from removednotificationsmaster where Userid=#userid) and nfl.UserId = #userid and nfl.RelatedSettingColumn = RelatedTo
Try This on MS SQL
WITH date_range (calc_date) AS (
SELECT DATEADD(DAY, DATEDIFF(DAY, 0, [ending date]) - DATEDIFF(DAY, [start date], [ending date]), 0)
UNION ALL SELECT DATEADD(DAY, 1, calc_date)
FROM date_range
WHERE DATEADD(DAY, 1, calc_date) <= [ending date])
SELECT P.[fieldstartdate], P.[fieldenddate]
FROM date_range R JOIN [yourBaseTable] P on Convert(date, R.calc_date) BETWEEN convert(date, P.[fieldstartdate]) and convert(date, P.[fieldenddate])
GROUP BY P.[fieldstartdate], P.[fieldenddate];
CREATE FUNCTION overlap_date(s DATE, e DATE, a DATE, b DATE)
RETURNS BOOLEAN DETERMINISTIC
RETURN s BETWEEN a AND b or e BETWEEN a and b or a BETWEEN s and e;
Another method by using BETWEEN sql statement
Periods included :
SELECT *
FROM periods
WHERE #check_period_start BETWEEN range_start AND range_end
AND #check_period_end BETWEEN range_start AND range_end
Periods excluded :
SELECT *
FROM periods
WHERE (#check_period_start NOT BETWEEN range_start AND range_end
OR #check_period_end NOT BETWEEN range_start AND range_end)
SELECT *
FROM tabla a
WHERE ( #Fini <= a.dFechaFin AND #Ffin >= a.dFechaIni )
AND ( (#Fini >= a.dFechaIni AND #Ffin <= a.dFechaFin) OR (#Fini >= a.dFechaIni AND #Ffin >= a.dFechaFin) OR (a.dFechaIni>=#Fini AND a.dFechaFin <=#Ffin) OR
(a.dFechaIni>=#Fini AND a.dFechaFin >=#Ffin) )
I am trying to refactor a code that consists of nested loops. For a similar repetitive code snippet, I am trying to write a function which consists of a 'continue' within. The loop is very long and I just want to include the if statement in the function.
def calc_indexes_for_rand_switch_on(self, switch_on, rand_time, max_free_spot, rand_window):
if np.any(self.daily_use[switch_on:rand_window[1]] != 0.001): # control to check if there are any other switch on times after the current one
next_switch = [switch_on + k[0] for k in np.where(self.daily_use[switch_on:] != 0.001)] # identifies the position of next switch on time and sets it as a limit for the duration of the current switch on
if (next_switch[0] - switch_on) >= self.func_cycle and max_free_spot >= self.func_cycle:
upper_limit = min((next_switch[0] - switch_on), min(rand_time, rand_window[1] - switch_on))
elif (next_switch[0] - switch_on) < self.func_cycle and max_free_spot >= self.func_cycle: # if next switch_on event does not allow for a minimum functioning cycle without overlapping, but there are other larger free spots, the cycle tries again from the beginning
continue
else:
upper_limit = next_switch[0] - switch_on # if there are no other options to reach the total time of use, empty spaces are filled without minimum cycle restrictions until reaching the limit
else:
upper_limit = min(rand_time, rand_window[1] - switch_on) # if there are no other switch-on events after the current one, the upper duration limit is set this way
return np.arange(switch_on, switch_on + (int(random.uniform(self.func_cycle, upper_limit)))) if upper_limit >= self.func_cycle \
else np.arange(switch_on, switch_on + upper_limit)
This is the function I am trying to write. The if statement is a part of bigger while loop in the main code. But, here this gives an error since there is no loop. How can I solve this?
You can return a sentinel value here, e.g. None and handle this in the caller.
So in your function:
elif (next_switch[0] - switch_on) < self.func_cycle and max_free_spot >= self.func_cycle: # if next switch_on event does not allow for a minimum functioning cycle without overlapping, but there are other larger free spots, the cycle tries again from the beginning
return None
And use it like:
while some_condition():
# do some stuff
...
result = calc_indexes_for_rand_switch_on(switch_on, rand_time, max_free_spot, rand_window)
if result is None:
continue
...
# do stuff with result
Is return better than yield? From what ive read it can be. In this case I am having trouble getting iteration from the if statement. Basically what the program does is take two points, a begin and end. If the two points are at least ten miles apart, it takes a random sample. The final if statement shown works for the first 20 miles from the begin point, begMi. nCounter.length = 10 and is a class member. So the question is, how can I adapt the code to where a return statement would work instead of a yield? Or is a yield statement fine in this instance?
def yielderOut(self):
import math
import random as r
for col in self.fileData:
corridor = str(col['CORRIDOR_CODE'])
begMi = float(col['BEGIN_MI'])
endMi = float(col['END_MI'])
roughDiff = abs(begMi - endMi)
# if the plain distance between two points is greater than length = 10
if roughDiff > nCounter.length:
diff = ((int(math.ceil(roughDiff/10.0))*10)-10)
if diff > 0 and (diff % 2 == 0 or diff % 3 == 0 or diff % 5 == 0)\
and ((diff % roughDiff) >= diff):
if (nCounter.length+begMi) < endMi:
vars1 = round(r.uniform(begMi,\
(begMi+nCounter.length)),nCounter.rounder)
yield corridor,begMi,endMi,'Output 1',vars1
if ((2*nCounter.length)+begMi) < endMi:
vars2 = round(r.uniform((begMi+nCounter.length),\
(begMi+ (nCounter.length*2))),nCounter.rounder)
yield corridor,begMi,endMi,'Output 2',vars1,vars2
So roughdiff equals the difference between two points and is rounded down to the nearest ten. Ten is then subtracted so the sample is taken from a full ten mile section; and that becomes diff. So lets say a roughDiff of 24 is rounded to 20, 20 - 10, diff + begin point = sample is taken from between mi 60 and 70 instead of between 70 and 80.
The program works, but I think it would be better if I used return instead of yield. Not a programmer.
return is not better, it's different. return says "I am done. Here is the result". yield says "here is the next value in a series of values"
Use the one that best expresses your intent.
Using yield makes your function a generator function, which means it will produce a series of values each time its (automatically created) next() method is called.
This is useful when you want to process things iteratively because it means you don't have to save all the results in a container and then process them. In addition, any preliminary work that is required before values can generated only has to be done once, because the generator created will resume execution of your code following the that last yield encountered — i.e. it effectively turns it into what is called a coroutine.
Generator functions quit when they return a value rather than yield one. This usually happens when execution "falls off the end" when it will return None by default.
From the looks of your code, I'd say using yield would be advantageous, especially if you can process the results incrementally. The alternative would be to have it store all the values in a container like a list and return that when it was finished.
I use yield in situations where I want to continue iteration on some object. However, if I wanted to make that function recursive, I'd use return.
This program is going through a web-based development environment and is actually my attempt to get what I need from itertools that I can't actually import in this case. I've changed the function somewhat to meet the naming requirements, but it should be basically the same. My current problem is that reversed() is not implemented, so I have to work around that. I tried creating a list with a for loop that iterated down, both inside and outside of this function. I also tried the current version without the ()s around it. Now I get an error that I'm out of range of the index when I run this. What are my alternatives to reversed?
def combinations_of_options(options, opt_len):
''' yields all combinations of option in specific length
'''
pool = tuple(options)
pool_len = len(pool)
if opt_len > pool_len:
return
indices = range(opt_len)
yield tuple(pool[index] for index in indices)
while True:
for index in (range(opt_len,-1,-1)): #this is the line that uses reversed
if indices[index] != index + pool_len - opt_len:
break
else:
return
indices[index] += 1
for dummy_index in range(index+1, opt_len):
indices[dummy_index] = indices[dummy_index-1] + 1
yield tuple(pool[index] for index in indices)
I have program that checks wheter a social security numer is valid or not. Right now the program is One big function that step by step checks the number i input for several anomalies.
I want to make this big function into several different ones but i have no idea how and also no idea how to call all functions in a row couse they will rely alot on the previous functions results. im gonna try to show how is looks like:
#i want to make this into a separate function
def numberchecker(number):
if number > 15:
print('bad')
#i want to make this into a separate function
number1 = number.replace('-', '')
number2 = number1.replace(' ', '')
#i want to make this into a separate function
month= int(number1[2:][:2])
if month > 13:
print('very bad')
how shall i do this when some of the functions will rely on each others variables :/
Your first part is already a function, but confuses numbers and strings:
def check_num(num):
return num <= 15
your second part into a string-processing function:
def process_num(num):
return str(num).replace("-", "").replace(" ", "")
and the third into a boolean function
def correct_month(str_num):
return 1 <= str_num[2:4] <= 12
Now string them together:
if check_num(num):
str_num = process_num(num)
if not correct_month(str_num):
print('very bad')
else:
print('bad')
The crucial part of what you are trying to do is to return a value (in these cases, two booleans and a string) at the end of the function, so other functions can carry on and use it.
If all you do is validation, have all functions return either True or False, for example:
def numberchecker (number):
return number > 15
Then you can do:
all([numberchecker, current_month, ....])