1

I am trying to add up the values found within some custom objects in Swift. I have the follow code working in a Playground:

//Custom Object
class EntryPack: NSObject{
  var date: String!
  var duration: Double!
  var customValues:[CustomValuePack] = [] //Nested array of objects declared below
}

//Another object to nest in the above
class CustomValuePack: NSObject{
  var name:String!
  var value: Double!
}

//Instantiate nested objects
let cv1 = CustomValuePack()
  cv1.name = "Day"
  cv1.value = 1.2
let cv2 = CustomValuePack()
  cv2.name = "Day"
  cv2.value = 1.3
let cv3 = CustomValuePack()
  cv2.name = "Night"
  cv2.value = 2.2

//Instantiate parent objects
let entry1 = EntryPack()
  entry1.date = "bingo"
  entry1.duration = 1.1

  entry1.customValues = [cv1, cv2]

let entry2 = EntryPack()
  entry2.date = "bingo"
  entry2.duration = 2.2

let entry3 = EntryPack()
  entry3.date = "dang"
  entry3.duration = 3.0

//Throw it all together into an array
var package = [entry1, entry2, entry3]

//Predicate for some filtering
let predicate = NSPredicate(format:"date = %@", "bingo")
let results = (package as NSArray).filteredArrayUsingPredicate(predicate) as! [EntryPack]

//Sum all the parent object durations
let sum = results.reduce(0.0) { $0 + $1.duration }

print(sum) // = 3.3

But now I want to add up the value for each CustomValuePack where the name is "Day".

I can't figure out how to do a similar reduce on a nested array of objects. I've tried something like this, but it yields a syntax error:

let sum2 = results.reduce(0.0) { $0.customValues + $1.customValues.value } //Error

How do I sum the value in a nested array of objects? I eventually want to apply an NSPredicate to filter by name = Day as well, but I'm not that far yet.

1
  • Why not apply a flatMap to flatten the arrays, then sum them? Currently, you're trying to take the sum of two arrays. Commented Jul 28, 2016 at 21:03

1 Answer 1

5

Given entries defined as follow

let entries = [entry1, entry2, entry3]

you can extract the CustomValues with name == "Day" and sum the value field with this code

let sum = entries
    .flatMap { $0.customValues }
    .filter { $0.name == "Day" }
    .map { $0.value }
    .reduce(0, combine: +)

Improvements

You are using Swift but for some reason there still is a lot of Objective-C into your code.

This is how i would refactor your code

struct EntryPack {
    let date: String
    let duration: Double
    let customValues:[CustomValuePack]
}

struct CustomValuePack {
    let name:String
    let value: Double
}

let cv1 = CustomValuePack(name: "Day", value: 1.2)
let cv2 = CustomValuePack(name: "Day", value: 1.3)
let cv3 = CustomValuePack(name: "Night", value: 2.2)

let entry1 = EntryPack(date: "bingo", duration: 1.1, customValues: [cv1, cv2])
let entry2 = EntryPack(date: "bingo", duration: 2.2, customValues: [])
let entry3 = EntryPack(date: "dang", duration: 3.0, customValues: [])

Please note that now EntryPack and CustomValuePack are structs which are value types.

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you for your thorough answer. I'm working on understanding it. It appears the .reduce with the combine above is returning 1.2 when the right answer should be 2.5.
@CliftonLabrum: Oh, let me check it
I have to dynamically create and combine the filters in my actual app which is why I'm using NSPredicate. As I understand it, my objects have to inherit from NSObject in order to use NSPredicate.
Never mind. The error was on my side. Thanks for your help!
@CliftonLabrum: Ok fine.

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.