0

I'm having difficulty wording this, but here goes.

I have an array of Datapoint objects and each of these objects has a createdAt NSDate property. The array has about 10 or so Datapoint objects for each day of the past week.

I want to filter the array so that there is only one datapoint for each day of the week.

I was thinking something along the lines of:

        let today = NSDate()
        var endRange = today.dateByAddingTimeInterval(-7 * 24 * 60 * 60)
        var allThisWeeksPoints = datapoints.filter({ $0.createdAt  >= endRange && $0.createdAt < today })
        let c = NSCalendar.currentCalendar()
        var thisWeeksPoints : [Datapoint] = []
        while !c.isDate(endRange, inSameDayAsDate: today) {
            //take one datapoint, eliminate all the other datapoints in the same day and then increment the endRange date by a day
        }

Here is the code for my Datapoint object:

class Datapoint: NSObject {
    let object : PFObject

    let objectId : String
    let userId : String
    let createdAt : NSDate
    let totalPosts : Int
    let followerCount : Int
    let followingCount : Int
    let totalLikes : Int
    let averageLikes : Float
    let totalComments : Int
    let averageComments : Float
}
R Menke
  • 8,183
  • 4
  • 35
  • 63
shakked
  • 783
  • 8
  • 24
  • please add your DataPoint code – R Menke Dec 11 '15 at 17:37
  • please add working code.... we can help you in seconds/minutes if we can copy paste your code in a playground – R Menke Dec 11 '15 at 17:41
  • I'm having trouble theoretically figuring out how to do it, I don't have any working code at the moment – shakked Dec 11 '15 at 17:43
  • 1
    Note that .dateByAddingTimeInterval(-7 * 24 * 60 * 60) may not be the same as a week time interval. You should use NSCalendar method dateByAddingUnit – Leo Dabus Dec 11 '15 at 17:44

2 Answers2

1

Step One:

Make NSDate Comparable Found here

public func ==(lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs === rhs || lhs.compare(rhs) == .OrderedSame
}

public func <(lhs: NSDate, rhs: NSDate) -> Bool {
    return lhs.compare(rhs) == .OrderedAscending
}

extension NSDate: Comparable { }

A few general remarks:

  • Use an input and output.
  • Respect upper and lower camel naming conventions

Split the function in two parts, one for dividing the points in weeks, another to apply the filter. This makes it easier to maintain.

Use dateByAddingUnit as suggested in the comments. This will prevent localisation issues. Not every week is the same and not every calendar used in the world uses the same system of weeks.

func weeklyPoints(dataPoints: [DataPoint]) -> [[DataPoint]]? {

    guard let firstPoint = dataPoints.first else { // alternative to an .isEmpty check since we need the first point anyway
        return nil
    }

    guard let gregorian = NSCalendar(identifier:NSCalendarIdentifierGregorian) else {
        return nil
    }

    var weeklies : [[DataPoint]] = [[]]
    var weekStart : NSDate = firstPoint.createdAt // force unwrap allowed because of the guard at the beginning
    var maybeWeekEnd : NSDate? = gregorian.dateByAddingUnit(.WeekOfYear, value: 1, toDate: weekStart, options: [])

    for point in dataPoints {

        guard let weekEnd = maybeWeekEnd else {
            break
        }

        guard point.createdAt >= weekStart && point.createdAt < weekEnd else {
            weekStart = weekEnd
            maybeWeekEnd = gregorian.dateByAddingUnit(.WeekOfYear, value: 1, toDate: weekStart, options: [])
            weeklies.append([])
            continue
        }

        let currentWeekIndex = (weeklies.count - 1)
        weeklies[currentWeekIndex].append(point)

    }

    return weeklies

}

The very simple filter function.

func onePointPerWeek(dataPoints: [DataPoint]) -> [DataPoint]? {

    guard let weeklies = weeklyPoints(dataPoints) else {
        return nil
    }

    var pointPerWeek : [DataPoint] = []

    for week in weeklies {
        guard let point = week.first else { // maybe sort them first if needed
            continue
        }
        pointPerWeek.append(point)
    }
    return pointPerWeek
}
Community
  • 1
  • 1
R Menke
  • 8,183
  • 4
  • 35
  • 63
0

So I figured out a way to do it:

func thisWeeksPoints() -> [Datapoint] {
        let today = NSDate()
        var endRange = today.dateByAddingTimeInterval(-7 * 24 * 60 * 60)
        var allThisWeeksPoints = datapoints.filter({ $0.createdAt  >= endRange && $0.createdAt < today })
        let c = NSCalendar.currentCalendar()
        var thisWeeksPoints : [Datapoint] = []
        while !c.isDate(endRange, inSameDayAsDate: today) {
            if let point = allThisWeeksPoints.first {
                allThisWeeksPoints = allThisWeeksPoints.filter({!c.isDate(point.createdAt, inSameDayAsDate: $0.createdAt)})
                thisWeeksPoints.append(point)
            }
            endRange = endRange.dateByAddingTimeInterval(24 * 60 * 60)
        }

        return thisWeeksPoints
    }
shakked
  • 783
  • 8
  • 24