2015-09-21 12 views
6

Wenn ich ein Array (z. B. für eine map()-Funktion, wo ich den Index eines Elements zusammen mit seinem Wert verwenden müsste) aufzählen möchte, könnte ich enumerate() Funktion verwenden. ZB:Wie man eine Scheibe unter Verwendung der ursprünglichen Indizes aufzählt?

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 

Nun, wenn ich eine Untersequenz aus dem Array verwenden möge, könnte ich ein slice, verwenden und es würde mir erlauben, nur die gleiche Indizes zu verwenden, wie ich in der ursprünglichen Anordnung verwenden würde (das ist genau das, was ich im Fall, wenn ich subscript Accessor in einer for Schleife verwenden würde). Z.B .:

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 

Allerdings sollte ich versuchen, enumerate().map() Ansatz zu verwenden, wie ich mit Original-Array haben, dann habe ich völlig anderes Verhalten zu bekommen. Statt slice ‚s Reihe von Indizes würde ich einen neuen bekommen, 0-basierten Bereich:

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

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

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

Frage ist, ob es eine anständige Art und Weise (dh ohne manuelle Anpassungen Offsets, oder etwas mit) eine Scheibe aufzuzuzählen mit seine eigenen Indizes und nicht die automatisch generierten 0-basierten?

+1

keine Antwort auf Ihre Frage, aber Sie können die for-Schleife ersetzen mit 'lassen powersSlice = Scheibe .indices.map {pow (slice [$ 0], Double ($ 0))} ' –

+0

Danke, @MartinR. Ich werde Ihren Vorschlag im Auge behalten als eine Umgehungslösung, die besser ist, als nur den 'enumerate'-generierten Indexbereich zu verrechnen. – courteouselk

Antwort

4

enumerate() gibt eine Sequenz von (n, elem) Paaren, wobei die n s aufeinanderfolgende Int s beginnend bei Null. Dies ist sinnvoll, weil es eine Protokollerweiterungsmethode für SequenceType ist, und eine willkürliche Sequenz hat nicht unbedingt Index mit den Elementen zugeordnet.

Sie würden Ihr erwartete Ergebnis mit

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

oder

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

Dieser Ansatz für eine Protokollerweiterung Verfahren für beliebige Sammlungen erhalten verallgemeinert werden könnten:

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

Diese gibt eine Sequenz von (index, elem) Paaren zurück wo index ist ein Index der Sammlung und elem das entsprechende Element. AnySequence wird verwendet, um den spezifischen Typ Zip2Sequence<RangeGenerator<Self.Index>, Self>, der von zip() vom Anrufer zurückgegeben wird, zu "verbergen".

Beispiel:

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

Update für Swift 3:

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

Ausgezeichnet. Vielen Dank. – courteouselk

Verwandte Themen