Home > database >  Using Reduce to sum (Swift)
Using Reduce to sum (Swift)

Time:05-25

Im looking through examples were you can use reduce to sum an array, but mostly finding examples with numbers. How would you add up all Bar that are inside Foo that has isAvailable set to true using reduce()? Would you prefer to write it as I've done or is there a better way? (for example with reduce)

struct Foo {
    var isAvailable: Bool
    var bars: [Bar]
}

struct Bar {
    var name: String
}

let array = [
    Foo(isAvailable: true, bars: [ Bar(name: "Bill"), Bar(name: "Donald") ]),
    Foo(isAvailable: false, bars: [ Bar(name: "Barack"), Bar(name: "Joe") ]),
    Foo(isAvailable: true, bars: [ Bar(name: "George"), Bar(name: "Ronald") ])
]


// Do this with reduce??
var totalCount = 0
for foo in array where foo.isAvailable {
    totalCount  = foo.bars.count
}

CodePudding user response:

In a short way:

let reduced = array.reduce(0) { $1.isAvailable ? $0   $1.bars.count : $0 }

Now, let's explicit it:

The logic is quite simple:

  • We set the initial value to 0
  • In the closure, we have two parameters, the first one is the current value (at start it's the initial value), which we'll increment at each iteration, and the second one is the element of the array. We return then the new value (partial) that we incremented or not according to your condition (here is isAvailable)

Explicitly:

let reduced2 = array.reduce(0) { partial, current in
    if current.isAvailable {
        return partial   current.bars.count
    } else {
        return partial
    }
}

With a ternary if:

let reduced3 = array.reduce(0) { partial, current in
    return current.isAvailable ? partial   current.bars.count : partial
}

Getting rid of the return, see Functions With an Implicit Return in Functions of Swift or Implicit Returns from Single-Expression Closures of Closures of Swift.

let reduced4 = array.reduce(0) { partial, current in
    current.isAvailable ? partial   current.bars.count : partial
}

With Shorthand Argument Names on Closures of Swift.

let reduced5 = array.reduce(0) { $1.isAvailable ? $0   $1.bars.count : $0 }

CodePudding user response:

let sum = array
    .filter { $0.isAvailable }
    .map { $0.bars.count }
    .reduce(0,  )

CodePudding user response:

You can achieve this using a single reduce operation. Start from a 0 result, then in the closure, check foo.isAvailable and only increment the count if it is true.

let totalCount = array.reduce(0, { accumulatingResult, foo in
  guard foo.isAvailable else { return accumulatingResult }
  return accumulatingResult   foo.bars.count
})
  • Related