2

I have this class:

class Post {
    var key: String
    var uid: String
    var minutes: Int
    var name: String
    let ref: FIRDatabaseReference?

init(key: String, uid: String, minutes: Int, name: String){
    self.key = key
    self.uid = uid
    self.minutes = minutes
    self.name = name
    self.ref = nil
}

Using this class I have created an array of objects, while I can total minutes I am having trouble totaling the minutes of only the elements having distinct uid.

Could someone help point me in the right direction?

3
  • What do you mean by I am having trouble totaling the minutes based on uid You want to sum of minutes with specific uids? If yes add details of that also in your question. Commented Mar 2, 2017 at 5:49
  • Yes, an array can have the same uid and I want the total minutes for each unique uid instance so that in the end I have the total minutes per unique uid. I will update the original post. Thanks! Commented Mar 2, 2017 at 6:20
  • You haven't update your question? Commented Mar 2, 2017 at 9:55

2 Answers 2

3

EDIT

My original answer missed the point of your question it seems, here is what you want:

let minutes = posts.reduce(([String : Int]())) { accumulator, value in
    var currentData = accumulator
    if accumulator.keys.contains(value.uid) {
        currentData[value.uid] = accumulator[value.uid]! + value.minutes
        return currentData
    } else {
        currentData[value.uid] = value.minutes
        return currentData
    }
}

This is playground code for totalling only the minutes of the unique uid:

 let posts = [Post(key: "key", uid: "0", minutes: 5, name: "name"), Post(key: "key", uid: "1", minutes: 5, name: "name"), Post(key: "key", uid: "1", minutes: 5, name: "name"), Post(key: "key", uid: "1", minutes: 5, name: "name"), Post(key: "key", uid: "3", minutes: 2, name: "name")]

 let count = posts.reduce((0, [String]())) { accumulator, value in
    if accumulator.1.contains(value.uid) {
        return accumulator
    } else {
        return (accumulator.0 + value.minutes, accumulator.1 + [value.uid])
    }
  }.0

The reduce lets you "iterate" over your posts array. You start with a minute count of 0 and and an empty uid array. If the uid is there then you don't add any minute to the minute count and you leave the array as is. If not, you add the minutes and add the string to the array of uid strings. At the end you get the minute count by getting the first element of the tuple (hence the .0)

the shorter version is:

   let count = posts.reduce((0, [String]())) {
       return $0.1.contains($1.uid) ? $0 : ($0.0 + $1.minutes, $0.1 + [$1.uid])
   }.0
Sign up to request clarification or add additional context in comments.

3 Comments

That worked, thanks so much! I really appreciate it. Not sure if this is appropriate here but quick follow-up: if I now wanted to only add up the minutes in certain date ranges how would I best integrate an if statement into the reduction so it only looks at posts between date A and date B?
Nevermind I got it by just adding an if statement right under the let count statement. Thanks again!
you can use a filter: minutes.filter { your condition here }. You condition should look like this $0.date > yourFirstDate && $0.date < yourSecondDate
2

With the newly defined question, what you're looking for would be something like:

let counts = values.reduce([String:Int]()) { acc, value in
    var copy = acc

    copy.updateValue((copy[value.uid] ?? 0) + value.minutes, forKey: value.uid)

    return copy
}

1 Comment

uid is of type String so you should edit your dictionary type and I can delete my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.