Reputation: 321
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 it? (readability & efficiency in mind)
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
}
Upvotes: 1
Views: 3491
Reputation: 26026
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:
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 }
Upvotes: 4
Reputation: 54716
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
})
Upvotes: 2
Reputation: 2859
let sum = array
.filter { $0.isAvailable }
.map { $0.bars.count }
.reduce(0, +)
Upvotes: 1