2015-09-21 11 views
6

Jeśli chcę wyliczyć tablicę (np. Dla funkcji map(), gdzie potrzebowałbym użyć indeksu elementu wraz z jego wartością), mógłbym użyć funkcji enumerate(). Np:Jak wyliczyć plasterek używając oryginalnych indeksów?

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 

Teraz, jeśli chcę korzystać z niektórych sub-sekwencji z tablicy, mogę użyć slice, a to pozwala mi używać tak samo indeksów jak użyłbym w oryginalnej tablicy (właśnie tego chcę w przypadku, gdybym użył akcesora subscript w pętli for). Np .:

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 

Należy jednak próbuję użyć enumerate().map() podejście jak ja z oryginalnej tablicy, a następnie uzyskać zupełnie inne zachowanie. Zamiast zakresie slice „s indeksów chciałbym dostać nowy, zakres 0 opartego:

let powersSliceEnumerate = slice.enumerate().map() { 
    pow($0.element, Double($0.index)) 
} 

print("powersSliceEnumerate == \(powersSliceEnumerate)") 

// powersSliceEnumerate == [1.0, 3.0] <- Not as expected 

Pytanie brzmi, czy jest to przyzwoity sposób (czyli bez ręcznych korekt z wykorzystaniem przesunięcia czy coś), aby wyliczyć kawałek korzystania własne indeksy, a nie te generowane automatycznie 0?

+1

Nie jest to odpowiedź na twoje pytanie, ale można zastąpić pętli for z 'niech powersSlice = plaster .indices.map {pow (wycinek [0 USD], Double (0 USD))} ' –

+0

Dzięki, @MartinR. Będę miał na uwadze twoją sugestię lepiej, niż tylko zrównanie zakresu indeksów generowanych przez wyliczenie. – courteouselk

Odpowiedz

4

enumerate() zwraca sekwencję (n, elem) par, gdzie n S są kolejne Int s od zera. Ma to sens, ponieważ jest to metoda przedłużenia protokołu dla SequenceType, a arbitralna sekwencja niekoniecznie musi mieć indeks powiązany z elementami.

Można by uzyskać oczekiwany rezultat z

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

lub

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

To ostatnie podejście można uogólnić do przedłużenia protokołu metody dowolnych zbiorów:

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

ten zwraca sekwencję par (index, elem) gdzie index jest indeksem kolekcji i elem odpowiedniego elementu. AnySequence służy do "ukrywania" określonego typu telefonu Zip2Sequence<RangeGenerator<Self.Index>, Self> zwrócony z zip() od osoby dzwoniącej.

Przykład:

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

Aktualizacja Swift 3:

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

Doskonały. Dziękuję Ci. – courteouselk

Powiązane problemy