简体   繁体   中英

Swift Filter and Map over array of structs

I may have this really wrong. Noob. I've recreated what I'm doing in a playground type environment here. Basically the sender is a slider within a UITableView of other sliders. The myData is the underlying data. I want to perform a calculation to all the items of the underlying data EXCEPT the one which corresponds to the sender item. I have no idea if my closure syntax is correct. This is the first time I'm creating one.

// 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

So basically I'm trying to use filter and map and the calcOtherVals closure to edit the array of structs in place. I can do this with conditionals and loops and calcOtherVals as a function no problem. Just hoping to do it more elegantly.

QUESTION: As in the code comment, I need to perform calcOtherVals on all the .value floats in myData EXCEPT the element at position sender.tag . How?

So as I understood you need to filter your array something like

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

then you use reduce to calculate

let sumAll = filterdData.reduce(0, {$0.value + $1.value})
myData.enumerated().flatMap { (index, element) in return index != sender.tag ? calcOtherVals (element.value) : nil }

Few bits of swift magic here. Firstly enumerate() returns an array of tuples containing the element, and the index of said element.

Next flatMap() . This is essentially map but it ignores any transform that resolves to nil. Great for converting from an optional array to a flat array, and also great if you wish to do a map+filter operation such as this.

-- Updated --

If you're comfortable with implicit arguments, you can reduce it further:

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

This Question is Already have an answer,

for better understanding you can review this very good tutorial about map, filter and reduce

Link:- https://useyourloaf.com/blog/swift-guide-to-map-filter-reduce/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM