Reputation: 1592
I have a swift code like below
var items: [Item] = []
for i in 0...20 {
items.append( makeItem(atIndex: i) )
}
would it be possible to rewrite above like
var items: [Item] = [0...20].map {
makeItem(atIndex: i)
}
Upvotes: 0
Views: 456
Reputation: 3256
To get your exact syntax, you can create the extension:
extension Array where Element == ClosedRange<Int> {
@discardableResult
func map(_ f: @escaping(Int) -> Void) -> [Int]{
var result : [Int] = []
for i in 0 ..< self[0].count {
result.append(i)
f(i)
}
return result
}
}
and call it like this:
let items = [0...50].map {
print($0) // current index
}
print(items)
Note that items will be [Int]
, this solves your question before your edits, when you just wanted to write a for
loop like this:
[0...50].map {
print($0) // current index
}
Upvotes: 0
Reputation: 16256
The syntax [0...20]
Is an array containing a single closed range of Int
, not an array of Int (which is what you would typically want to call map()
on ), so what you really want is:
let integers = [
0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16,
17 ,18, 19, 20]
integers.map{
// your code here
}
(My original answer missed this distinction, I have corrected it now. See other answers on how to convert a range into an array of Int
)
Both will execute the block within the brackets 21 times, one for each integer in the array.
But in contrast to the for
loop, the map()
function is expected to return an array of some type, where each element is obtained by transforming each of the elements in the original array (in this case, the integers 0
through 20
) into an instance of the resulting type. For example:
let textRepresentations: [String] = integers.map {
return "\($0)"
}
// Now textRepresentations contains "0", "1", etc.
If your goal is to assemble an array out of objects created based on those 21 integers, map()
gives you a more elegant solution than you would have done in a more "C-like" way, e.g.:
var textRepresentations: [String] = []
for i in 0 ... 20 {
textRepresentations.append("\(i)")
}
But if you only need to execute some logic once for each of those integers, with no array left as a result, using map()
(and discarding the result) will look awkward and confusing to people have to maintain that code (including your future self).
Additionally, a more "Swifty" alternative to the for ... in
loop is foreach
(which looks a bit more like map()
, minus the returned array):
integers.foreach {
// (use $0 instead of i)
}
...or, more verbosely:
integers.foreach { (element) in
// (use `element`, of course)
}
Upvotes: 1
Reputation: 19912
It's possible, just don't wrap the range in an array, so use (0...20)
instead of [0...20]
You can even pass the name of the function and you won't have to create a closure with a single call.
let items = (0...20).map(makeItem)
Upvotes: 3