1

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?

1
  • 1
    I think that I didn't got it right, you want to map myData and filter it to get all data based on what? myDataStruct does not has a tag property. could you elaborate? Commented Jun 5, 2017 at 7:58

3 Answers 3

5
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 }
Sign up to request clarification or add additional context in comments.

1 Comment

That's not type inference, that's implicit arguments. Type inference is going on either way, since you never specify the types for anything.
3

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})

2 Comments

So you're saying I need to add a tag / id value to the myData struct?
yes, something to identify. if your values are unique for example it's between [0...100] then you don't need extra field and you can use value as tag
-1

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/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.