Reputation: 41
I am working on a function that takes the total cost of all the "MP" in a value and adds it up. Here is my code for context.
typealias Spell = (name: String, cat: Category, cost: Int)
let startingSpellList: [Spell] = [
("Poison", .attack, 3),
("Bio", .attack, 26),
("Fire", .attack, 4),
("Fire 2", .attack, 20),
("Fire 3", .attack, 51),
("Ice", .attack, 5),
("Ice 2", .attack, 21),
("Ice 3", .attack, 52),
("Bolt", .attack, 6),
("Bolt 2", .attack, 22),
("Bolt 3", .attack, 53),
("Pearl", .attack, 40),
("Quake", .attack, 50),
("Break", .attack, 25),
("Doom", .attack, 35),
("Flare", .attack, 45),
("Meteor", .attack, 62),
("Ultima", .attack, 80),
Here is the function :
func totalCost(_ spells: [Spell]) -> Int {
let cost = spells.cost
let sum = cost.reduce(0, +)
return sum
}
With this code, I get the error that `"Value of type '[Spell]' (aka 'Array<(name: String, cat: Category, cost: Int)>') has no member 'cost'." How should I fix this error?
Upvotes: 3
Views: 112
Reputation:
rob mayoff's answer is great, but everybody needs this stuff all the time, so you should put your own extensions in a reusable package until they get included in the standard library.
startingSpellList.map(\.cost).sum
startingSpellList.reduce(\.cost, +)
public extension Sequence {
/// - Returns: `nil` If the sequence has no elements, instead of an "initial result".
func reduce(
_ nextPartialResult: (Element, Element) throws -> Element
) rethrows -> Element? {
var iterator = makeIterator()
return try iterator.next().map { first in
try IteratorSequence(iterator).reduce(first, nextPartialResult)
}
}
/// Accumulates transformed elements.
/// - Returns: `nil` if the sequence has no elements.
func reduce<Result>(
_ transform: (Element) throws -> Result,
_ getNextPartialResult: (Result, Result) throws -> Result
) rethrows -> Result? {
try lazy.map(transform).reduce(getNextPartialResult)
}
}
public extension Sequence where Element: AdditiveArithmetic {
var sum: Element? { reduce(+) }
}
Upvotes: 0
Reputation: 385760
spells
is a [Spell]
, which is shorthand for Array<Spell>
, and Array<Spell>
doesn't have a cost
property. Each individual Spell
in the array has its own cost
property. You could say this to get an array of the spell costs and sum the costs array:
func totalCost(_ spells: [Spell]) -> Int {
let costs = spells.map { $0.cost }
let sum = costs.reduce(0, +)
return sum
}
Or you could use a key-path literal, which can act as a function:
func totalCost(_ spells: [Spell]) -> Int {
let costs = spells.map(\.cost)
let sum = costs.reduce(0, +)
return sum
}
However, using map
that way creates a temporary array to hold the costs, and that's wasteful. You can avoid the temporary array by using the .lazy
operator first:
func totalCost(_ spells: [Spell]) -> Int {
let costs = spells.lazy.map(\.cost)
let sum = costs.reduce(0, +)
return sum
}
Or you can fuse the extraction of cost
and the summation:
func totalCost(_ spells: [Spell]) -> Int {
let sum = spells.reduce(0) { $0 + $1.cost }
return sum
}
Upvotes: 3