Reputation: 1275
i've transformed a nested for
loop into a nested map
call. i was wondering if there was a more elegant way to implement it.
here is a function that takes in an Array
of Item
s and an Array
of functions (Item -> Item
) and returns an array with all of the functions applied to each item:
typealias Item = Dictionary<String, String>
func updatedItems(items: Array<Item>, fns: Array<Item -> Item>) -> Array<Item> {
return items.map {
item in
var itemCopy = item
fns.map { fn in itemCopy = fn(itemCopy) }
return itemCopy
}
}
Upvotes: 2
Views: 1191
Reputation: 539955
The inner map()
call does not return a new array, it is done merely for the side-effects. This works, but is sometimes "frowned-upon" (see
for example Higher order function: "Cannot invoke 'map' with an argument list of type '((_) -> _)'").
The "proper" way to apply all functions in turn to a single item is
to use reduce
:
func updatedItems(items: Array<Item>, fns: Array<Item -> Item>) -> Array<Item> {
return items.map {
item in
fns.reduce(item) {
(curItem, fn) in
fn(curItem)
}
}
}
or with shorthand argument names:
func updatedItems(items: Array<Item>, fns: Array<Item -> Item>) -> Array<Item> {
return items.map {
fns.reduce($0) { $1($0) }
}
}
Note also that you can shorten the array notation to
func updatedItems(items: [Item], fns: [Item -> Item]) -> [Item] { ... }
Upvotes: 4
Reputation: 80273
Another solution is to use enumerate
in order to also have access to the index.
return items.enumerate().map { (idx, item) in
let fn = fns[idx] as <Item -> Item>
return fn(item)
}
Upvotes: 2