UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Filtering the array of structs by another array of dates

Forums > Swift

Good day, everyone! I've got some entry-level question, so don't be too harsh on me.

I'm developing iExpence example project further, and I want the sum of user spendings for a week.

I've got a struct...

struct CashItem: Identifiable, Hashable {
    let id = UUID()
    let date: Date
    let sum: Double
}

...and a published class.

class Money: ObservableObject {
    @Published var cash = [CashItem]()

Now, I'm trying to build a function to filter it all. In folded function I return an array of days of current week, and then I'm trying to apply it to the filtered array.

func currentWeekCash() -> Double {
        let calendar = Calendar.current
        let startOfCurrentWeek = calendar.date(from: calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: Date()))
        func getWeekDates(of startDate: Date, with calender: Calendar) -> [Date] {
            var weekDates: [Date] = []
            for i in 0..<7 {
                weekDates.append(calendar.date(byAdding: .day, value: i, to: startDate)!)
            }
            return weekDates
        }
        let currentWeekDates = getWeekDates(of: startOfCurrentWeek!, with: calendar)

        func targetDataArray() -> [Double] {
            let targetDataArray = money.cash.map ({ $0.sum }).filter {
                for i in currentWeekDates {
                    Calendar.current.isDate(money.cash.map ({ $0.date }), equalTo: i, toGranularity: .day)
                }
            }
        }
        let targetData = targetDataArray().reduce(0.0, +)

        return targetData
    }

Now, I've got a responce of Cannot convert value of type '[Date]' to expected argument type 'Date', which makes sense, but if I'm trying to make loop over loop, it returns me type of [()]. It makes no sense at all.

So, I'm a little completely confused.

2      

Your problem is here:

Calendar.current.isDate(money.cash.map ({ $0.date }), equalTo: i, toGranularity: .day)

money.cash.map ({ $0.date }) converts an array of CashItems into an array of Dates.

Calendar.isDate(_:equalTo:toGranularity:) takes a single Date as its first parameter.

You are attempting to pass an array of Dates to a parameter that is expecting a single Date.


To be honest, almost all of your currentWeekCash function is really unnecessary.

  • You don't need to build an array of the current week's days because you can use Calendar.isDate(_:equalTo:toGranularity:) directly in the filter to check that your dates are in the current week.
  • You don't need a separate nested function to generate an array of targetData that you then separately call reduce(_:_:) on because you can do it all at once by chaining methods together.

So we can lose getWeekDates(of:with:) and targetDataArray() and all the stuff that goes with them.

Instead we can boil currentWeekCash down to something like this:

func currentWeekCash() -> Double {
    //for ease of use...
    let cal = Calendar.current

    //now we just get our results
    //1. filter the CashItems for dates in the current week
    //2. reduce their sums to a single Double value
    return money.cash.filter {
        //$0 will be a CashItem instance
        //so we want to get the .date property
        //and check if it's in the same week as today
        cal.isDate($0.date, equalTo: Date.now, toGranularity: .weekOfYear)
    }
    //$0 will be the accumulated result (a Double)
    //$1 is the next CashItem in our filtered array
    .reduce(0.0) { $0 + $1.sum }
}

Also, it seems to me that currentWeekCash is likely a method on a SwiftUI View that calculates this data from an ObservedObject or EnvironmentObject called money. It probably should be pulled out of the View and turned into a method on the Money class instead, as it's a function of that class' data rather than anything specifically View related. A commputed property on Money might be even better.

3      

Whoa, it really boils down to 4 lines.

Thanks a lot, gonna practice more!

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.