Calculating data based on calendar dates that may potentially go on forever

96 Views Asked by At

Not really a language specific question, but my language in use in the examples below is Swift. The code itself is written to be somewhat language agnostic.

public class Employment {

    public var payFrequency: PayFrequency

    public var payPeriods: [PayPeriod]

    // Other class data, variables, etc.

    // Constructors, other functions, etc.

    public func calculatePayPeriods(payBegin: NSDate) {
        self.payPeriods = [] // Null out array
        // Enter loop to the extent of calculation.. Infinity?
        // Create the PayPeriod object with start, end, and # of hours worked.
        // Advance # of days based on payFrequency
    }
}

Now I have only included the respective variable(s) and function(s). My question in particular is obviously on the calculatePayPeriods(...) function. This function in particular will be called once the user inputs a single pay period start date. Since I obviously, or well practically, cannot generate the pay periods until the end of time and would prefer not to do year-by-year. My question is as follows: what sort of implementation would best suit a situation where the data being calculated can potentially span infinitely?

Here is the implementation, and a helper function if needed for reference:

public struct PayPeriod {

    public var startDate: NSDate

    public var endDate: NSDate

    public var hours: Double

}

// Returns .Other(amount); 'amount' being in days.
// If 'amount' is compatible with any other case in the enum, then instead that
// case is returned.
public func determinePayFrequency(start: NSDate, end: NSDate) -> PayFrequency {
    let converter: Double = 60*60*24 // 60 seconds 60 minutes 24 hours
    let calendar = NSCalendar.currentCalendar()
    let unit = NSCalendarUnit.CalendarUnitDay
    let componentFlags = NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay

    // Strip away any extra components we don't need such as hour/min/sec/etc.
    var startDay = calendar.dateFromComponents(calendar.components(componentFlags, fromDate:start))!
    var endDay = calendar.dateFromComponents(calendar.components(componentFlags, fromDate:end))!

    // '+ 1' is to go THROUGH the end day.
    return PayFrequency(days: Int(endDay.timeIntervalSinceDate(startDay) / converter) + 1)
}

I appreciate the time you took to read over my question and code. Thank you.

Best regards,

Steven

2

There are 2 best solutions below

0
On

From what I understand, you want to basically give the user a reasonable range of dates initially and then populate dynamically if they request more. This is a really common practice.

For example, facebook's public home page does not have all the posts that they need in 1 huge page. Instead, they delegate only x amount of posts on the screen at once. Once the user scrolled to the bottom, there would be more loaded.

From what I understand, the background behind this is that facebook has a database that it's constantly retrieving json/xml data from to populate your public home page. Requests that are too big(in your case, infinitely big) would have to be truncated down to x amount, then facebook's cookies hold a variable as to where to retrieve data from in the database again.

The same can be applied with your algorithm. If you feel that the retrievals are VERY frequent, then you should keep a dynamic array(that can reallocate size, commonly by 2x the previous size if needed) and add Day objects until the biggest submission. The ones that request times that are greater than the array size should trigger a function to populate the array to be just big enough to hold the data. If they're not too frequent, you could even just compute a calendar from start date to end date for every entry, and the time would not be inefficient either.

Hope I helped!

0
On

The short answer:

http://en.wikipedia.org/wiki/Lazy_evaluation#Working_with_infinite_data_structures

The long answer:

You do not calculate the list. You do not set the list. You compute the (read-only) list for the (concrete, finite) index N, potentially using cached elements at the index N'