How to list a fragment using source indexes?

If I want to list an array (say, for the map() function, where I will need to use the index of the element along with my value), I could use the enumerate() function. For instance:.

 import Foundation let array: [Double] = [1, 2, 3, 4] let powersArray = array.enumerate().map() { pow($0.element, Double($0.index)) } print("array == \(array)") print("powersArray == \(powersArray)") // array == [1.0, 2.0, 3.0, 4.0] // powersArray == [1.0, 2.0, 9.0, 64.0] <- As expected 

Now, if I want to use some subsequence from an array, I could use slice , and this would allow me to use only the same indexes as in the original array (this is exactly what I want if I used a subscript accessor in a loop for ). For instance:.

 let range = 1..<(array.count - 1) let slice = array[range] var powersSlice = [Double]() for index in slice.indices { powersSlice.append(pow(slice[index], Double(index))) } print("powersSlice == \(powersSlice)") // powersSlice == [2.0, 9.0] <- As expected 

However, if I try to use the enumerate().map() approach, as I did with the original array, then I get a completely different behavior. Instead of the range of slice indices, I would get a new range of 0:

 let powersSliceEnumerate = slice.enumerate().map() { pow($0.element, Double($0.index)) } print("powersSliceEnumerate == \(powersSliceEnumerate)") // powersSliceEnumerate == [1.0, 3.0] <- Not as expected 

The question is, is there a decent way (i.e., without manual settings using offsets or something else) for listing a slice using its own indices, and not with auto-generated 0-based ones?

+6
source share
1 answer

enumerate() returns a sequence of pairs (n, elem) , where n are consecutive Int , starting at zero. This makes sense because it is a protocol extension method for SequenceType and an arbitrary sequence does not necessarily have an index associated with the elements.

You will get the expected result with

 let powersSlice = slice.indices.map { pow(slice[$0], Double($0)) } 

or

 let powersSlice = zip(slice.indices, slice).map { pow($1, Double($0)) } 

The latter approach can be generalized to an extension of the protocol method for arbitrary collections:

 extension CollectionType { func indexEnumerate() -> AnySequence<(index: Index, element: Generator.Element)> { return AnySequence(zip(indices, self)) } } 

This returns a sequence of pairs (index, elem) , where index is the index of the collection and elem is the corresponding element. AnySequence used to "hide" a particular type of Zip2Sequence<RangeGenerator<Self.Index>, Self> returned from zip() from the caller.

Example:

 let powersSliceEnumerate = slice.indexEnumerate().map() { pow($0.element, Double($0.index)) } print("powersSliceEnumerate == \(powersSliceEnumerate)") // powersSliceEnumerate == [2.0, 9.0] 

Update for Swift 3:

 extension Collection { func indexEnumerate() -> AnySequence<(Indices.Iterator.Element, Iterator.Element)> { return AnySequence(zip(indices, self)) } } 
+4
source

All Articles