2015-09-21 24 views
6

Se desidero enumerare una matrice (ad esempio per una funzione map() in cui avrei bisogno di utilizzare l'indice di un elemento insieme al suo valore), potrei usare la funzione enumerate(). Ad esempio:Come enumerare una sezione utilizzando gli indici originali?

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 

Ora, se voglio utilizzare alcuni sotto-sequenza dalla matrice, che potrebbe utilizzare un slice, e mi avrebbe permesso di usare solo gli stessi indici come avrei usato nella matrice originale (che è proprio quello che voglio nel caso in cui io userò l'accessor subscript in un ciclo for). Es .:

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 

Tuttavia, devo cercare di utilizzare enumerate().map() approccio come ho fatto con matrice originale, allora ottengo un comportamento completamente diverso. Invece di gamma di indici di slice s' Vorrei avere una nuova, gamma 0-based:

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

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

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

domanda è se c'è un modo decente (cioè senza regolazioni manuali utilizzando offset, o qualcosa del genere) per enumerare una fetta utilizzando i suoi propri indici e non quelli a 0 generati automaticamente?

+1

una risposta alla tua domanda, ma è possibile sostituire il ciclo for con 'lasciare powersSlice = fetta .indices.map {pow (slice [$ 0], Double ($ 0))} ' –

+0

Grazie, @ Martin. Terrò a mente il tuo suggerimento come soluzione alternativa alla semplice compensazione della gamma di indici generati dall'enumerazione. – courteouselk

risposta

4

enumerate() restituisce una sequenza di coppie (n, elem), dove gli n s sono Int s consecutivi a partire da zero. Questo ha senso perché è un metodo di estensione del protocollo per SequenceType e una sequenza arbitraria non ha necessariamente un indice associato agli elementi.

Si potrebbe ottenere il risultato atteso con

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

o

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

Il secondo approccio potrebbe essere generalizzati ad un metodo di estensione del protocollo per le collezioni arbitrarie:

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

Questo restituisce una sequenza di coppie (index, elem) dove index è un indice della raccolta e elem l'elemento corrispondente. AnySequence viene utilizzato per "nascondere" il tipo specifico Zip2Sequence<RangeGenerator<Self.Index>, Self> restituito da zip() dal chiamante.

Esempio:

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

Aggiornamento per Swift 3:

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

Eccellente. Grazie. – courteouselk

Problemi correlati