2017-06-05 3 views
1

Ich kann das wirklich falsch haben. Anfänger. Ich habe das, was ich hier mache, in einer Spielplatzumgebung nachgebildet. Grundsätzlich ist der Absender ein Schieberegler innerhalb einer UITableView anderer Schieberegler. Die myData sind die zugrunde liegenden Daten. Ich möchte eine Berechnung für alle Elemente der zugrunde liegenden Daten durchführen, mit Ausnahme der, die dem Absender entspricht. Ich habe keine Ahnung, ob meine Closingsyntax korrekt ist. Dies ist das erste Mal, dass ich eines erstelle.Swift Filter und Map über Array von Strukturen

// sender comes over as a struct 
struct myStruct { 
    var tag: Int = 0 
    var value: Float = 0 
} 
let sender = myStruct(tag: 1, value: 199) 

// some vars for the calculation 
let globalTotal: Float = 597 
let globalAnotherTotal: Float = 0 

// an array of data structs 
struct myDataStruct { 
    var name: String = "" 
    var value: Float = 0 
} 
var myData: [myDataStruct] = [] 
myData.append(myDataStruct(name: "Tom", value: 45.0)) 
myData.append(myDataStruct(name: "Dick", value: 16.4)) 
myData.append(myDataStruct(name: "Harry", value: 12.3)) 

// a closure to do the calculation 
var calcOtherVals: (Float, Float) -> (Float) = { (startVal, senderStartVal) in 

    let remainingStartVals = globalTotal - senderStartVal 
    let remainingNewVal = globalTotal - sender.value - globalAnotherTotal 

    let endVal = ((startVal * (100/remainingStartVals))/100) * remainingNewVal 

    return endVal 
} 

// now need to perform calcOtherVals on all the .value floats in myData EXCEPT the element at position sender.tag hopefully using filter and map 

Also im Grunde versuche ich, Filter zu verwenden und Karte und die calcOtherVals Schließung der Array von Strukturen an Ort und Stelle zu bearbeiten. Das kann ich mit conditionals und loops und calcOtherVals als Funktion kein Problem machen. Ich hoffe nur, es eleganter zu machen.

FRAGE: Wie im Code-Kommentar, muss ich calcOtherVals auf alle Werte .value in myData durchführen, mit Ausnahme des Elements an der Position sender.tag. Wie?

+1

Ich denke, dass ich es nicht richtig verstanden habe, Sie wollen 'myData' abbilden und filtern, um alle Daten basierend auf was zu bekommen? 'myDataStruct' hat keine' tag' Eigenschaft. Könntest du es ausarbeiten? –

Antwort

1
myData.enumerated().flatMap { (index, element) in return index != sender.tag ? calcOtherVals (element.value) : nil } 

Nur wenige Bits von schnellen Magie zu berechnen. Zuerst gibt enumerate() ein Array von Tupeln zurück, die das Element und den Index dieses Elements enthalten.

Nächste flatMap(). Dies ist im Wesentlichen map, aber es ignoriert jede Transformation, die zu Null aufgelöst wird. Großartig für die Konvertierung von einem optionalen Array in ein flaches Array und auch großartig, wenn Sie eine Map + Filter-Operation wie diese durchführen möchten.

- Aktualisiert -

Wenn Sie mit impliziten Argumenten vertraut sind, können Sie es weiter reduzieren:

myData.enumerated().flatMap { $0.offset != sender.tag ? calcOtherVals ($0.element.value) : nil } 
+0

Das ist keine Typ-Inferenz, das sind implizite Argumente. Typ-Inferenz wird in beide Richtungen ausgeführt, da Sie die Typen nie für irgendetwas angeben. –

+0

Richtig bist du, danke @MichaelMorris – XmasRights

1

So wie ich verstanden müssen Sie Ihr Array so etwas wie

let filteredData = myData.filter({$0.tag != sender.tag}) 

dann filtern Sie reduzieren verwenden hier

let sumAll = filterdData.reduce(0, {$0.value + $1.value}) 
+0

Sie sagen also, ich muss der myData-Struktur einen Tag/ID-Wert hinzufügen? – Sean

+0

ja, etwas zu identifizieren. Wenn Ihre Werte eindeutig sind, zum Beispiel zwischen [0 ... 100] dann brauchen Sie kein zusätzliches Feld und Sie können den Wert als Tag verwenden –