Sheikh Atif
Sheikh Atif

Reputation: 137

Convert loop into swift higher order function

I am writing an iOS App in Swift 4.2 I am looping through array 1 and making changes to its one element and adding those elements to array 2.

Array:

let array:[model] = []
let array2:[model] = []

Model for this array is:

class model: NSObject {
    var id:Int = 0
    var name:String=""
    var isChecked:Bool=false
}

Function:

    func customCheckboxValueChangedWithID(_ id: Int, isChecked: Bool) {
array2.removeAll()
            //TODO, use sugar syntax/higher order function for this loop:
            for element in array{
                if(element.id==id){
                    element.isChecked=isChecked
if(element.isChecked){
array2.append(element)
}
                }
            }
            reloadCollectionView()
        }

How to convert this into swift higher order function, like map, flatMap, etc?

Upvotes: 2

Views: 3027

Answers (6)

Vodǎ
Vodǎ

Reputation: 3536

You can try this:

class MyObj: CustomStringConvertible {
    var id: String
    var isChecked: Bool

    init(id: String = "", isChecked: Bool = false) {
        self.id = id
        self.isChecked = isChecked
    }

    var description: String {
        return "MyObj(id: \(id), isChecked: \(isChecked)"
    }
}

let array = [
    MyObj(id: "id1"),
    MyObj(id: "id1", isChecked: true),
    MyObj(id: "id2"),
    MyObj(id: "id3", isChecked: true)
]

func customCheckboxValueChanged(_ values: [MyObj], id: String, isChecked: Bool) -> [MyObj] {
    let sameIDModels: [MyObj] = values
        .filter { $0.id == id }
        .map { $0.isChecked = isChecked; return $0 }

    return sameIDModels.filter{ $0.isChecked }
}

let isChecked = true
let myID = "id1"

print(customCheckboxValueChanged(array, id: myID, isChecked: isChecked))

Upvotes: 0

delavega66
delavega66

Reputation: 985

You can use Filter

numbers.forEach({ if $0.id == id { $0.isChecked = isChecked } })(Copied SPatel's comment)

Loops over a collection and returns an array that contains elements that meet a condition.

Let’s assume we need to filter even numbers only in the following array example. The traditional approach can be:

let numbersArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15]

// The traditional way
var evenNumArray: [Int] = []
for number in numbersArray {
  if number % 2 == 0 {
    evenNumArray.append(number)
  }
}
// evenNumArray = [2, 4, 6, 8, 10, 14]

Instead, let’s use filter for the same result:

let numbersArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15]
// Filter
let evenArray = numbersArray.filter { $0 % 2 == 0 }

Simple Higher Order Functions in Swift

Upvotes: 0

Kang-hee Lee
Kang-hee Lee

Reputation: 21

how about using 'flatMap'

here is playground source

//: Playground - noun: a place where people can play

import UIKit

struct model {
    var id:Int = 0
    var name:String=""
    var isChecked:Bool=false
}

let array:[model] = [model(id: 0, name: "0", isChecked: false),
model(id: 1, name: "1", isChecked: false),
model(id: 2, name: "2", isChecked: false),
model(id: 3, name: "3", isChecked: false),
model(id: 4, name: "4", isChecked: false),
model(id: 5, name: "5", isChecked: false),
model(id: 6, name: "6", isChecked: false)
]
var array2:[model] = []


func customCheckboxValueChangedWithID(_ id: Int, isChecked: Bool) {
    array2 = array.flatMap { (ma: model) -> model? in
        var element = ma

        if element.id == id {
            element.isChecked = isChecked
            return element
        }
        return nil
    }
}


customCheckboxValueChangedWithID(1, isChecked: true)
print("array2 : \(array2)")

result: array2 : [__lldb_expr_53.model(id: 1, name: "1", isChecked: true)]

Upvotes: 0

Fogmeister
Fogmeister

Reputation: 77651

You can rewrite this like...

array.forEach {
    if $0.id == someID { $0.isChecked = isChecked }
}

This only works because you are using classes.

If you switch to using structs then you could have...

let newArray = array.map {
    if $0.if == someID {
        var theModel = $0
        theModel.isChecked = isChecked
        return theModel
    }
    return $0
}

Upvotes: 0

Sulthan
Sulthan

Reputation: 130152

Since you have an array of classes, this is very simple:

let array: [model] = [...]

array.first { $0.id == id }?.isChecked = isChecked

If you had an array of structs, you would either need to update the original array or create a whole new array:

var array: [model] = []

// updating element in the original array
if let index = array.index(where: { $0.id == id }) {
   array[index].isChecked = isChecked
}

// updating the whole array
array = array.map {
   guard $0.id == id else { return $0 }
   var element = $0
   element.isChecked = isChecked
   return element 
}

Upvotes: 1

Mo Abdul-Hameed
Mo Abdul-Hameed

Reputation: 6110

You can do it this way:

array.forEach { if $0.id == id { $0.isChecked.toggle() } }

If you just want to filter the elements and only leave the elements whose isChecked property set to true, you can use this:

let newArray = array.filter { $0.isChecked }

Upvotes: 6

Related Questions