Replace Specific Value in Array of Object swift 5 - ios

I need to change values in array of object
Array of selected sports which is received from API
Update API Response
arrSelectedID = [["slug": cricket,
"id": 1,
"banner_image": https://_1558964043.jpg,
"name": Cricket,
"icons": {
black = "https://sport_icon_cricket_black.png";
green = "https://sport_icon_cricket_green.png";
grey = "https://sport_icon_cricket_gray.png";
white = "https://sport_icon_cricket_white.png";
}],
["slug": soccer,
"banner_image": https://1558964051.jpg
"icons": {
black = "https://sport_icon_soccer_black.png";
green = "https://sport_icon_soccer_green.png";
grey = "https://sport_icon_soccer_gray.png";
white = "https://sport_icon_soccer_white.png";
},
"id": 2,
"name": Soccer]]
My Array
struct ObjSportsList:Codable {
var id:Int
var name:String
var slug:String
var selected:Bool?
var icons:ObjSportsIcon
}
struct ObjSportsIcon:Codable {
var green:String
var grey:String
var white:String
var black:String
}
var arrSports:[ObjSportsList] = [] // Array which is custom object
Below response is printed my custom object "ObjSportsList"
arrSports = (id: 1,
name: "Cricket",
slug: "cricket",
selected: nil,
),
(id: 2,
name: "Soccer",
slug: "soccer",
selected: nil,
),
(id: 3,
name: "Baseball",
slug: "baseball",
selected: nil,
),
I want to change "selected" values = true which is get id from API array in "data" Example : [1,3] only change 1st and 3rd selected values == true
I try to work with below code but array not updated
for (index, var sports) in self.arrSports.enumerated() {
for selectedSports in arrSelectedID {
if selectedSports["id"] as! Int == sports.id {
sports.selected = true
}
}

Please refer below code to replace the specific value in Array of object
let aryIDS = [1,3]
for (index, sport) in arrSports.enumerated(){
if aryIDS.contains(sport.id) {
arrSports[index].selected = true
}
}
print(arrSports) //Received updated array

I fix the issue with my own code, Please check this code
for (index, sports) in self.arrSports.enumerated() {
for selectedSports in arrSelectedID {
if selectedSports["id"] as! Int == sports.id {
self.arrSports[index].selected = true
}
}
}

Related

How to extract one type of value from an array to create a separate array one by one?

I am trying to extract just the id's from the Properties Array to form a separate array. So far I have come up with this:
struct Interactions: View {
#State var A: [Properties] = [
.init(id: 5, name: "Five"),
.init(id: 8, name: "Eight"),
.init(id: 2, name: "Two")
]
var body: some View {
List(loadIdArray(), id: \.self) { i in
Text("\(i)")
}
}
func loadIdArray() -> [Int] {
let ids: [Int] = [1, 2]
for i in 0 ..< self.A.count {
let ids = [self.A[i].id, self.A[i + 1].id]
return ids
}
return ids
}
}
The problem is that I would have to manually type each [self.A[I + ...].id] which defeats the purpose of the function.
The answer I want is for loadIdArray() = [5, 8, 2] and for it to do this automatically depending on how many items are in the 'A' array.
how about using this:
func loadIdArray() -> [Int] {
return self.A.map { $0.id }
}

How to filter object-array with duplicated items name based on conditions in Swift

I have an object array with duplicated object properties value for some objects and I need to filter it according to some object properties conditions
I have something similar to the following code:
Model:
struct MyObject {
var name: String
var id: String
var times: Int
var value: Double
}
Array:
Let objectArray = [
MyObject(name: “Obj1”, id: “123”, times: 1, value: 3.0),
MyObject(name: “Obj2”, id: “456”, times: 1, value: 2.3),
MyObject(name: “Obj3”, id: “789”, times: 1, value: 1.0),
MyObject(name: “Obj2”, id: “456”, times: 2, value: 3.3),
MyObject(name: “Obj2”, id: “456”, times: 3, value: 4.7),
MyObject(name: “Obj4”, id: “212”, times: 1, value: 2.4)
]
I have implemented an extension Array function to remove the duplicated items in array but it's not enough on this case:
func filterDuplicate<T>(_ keyValue:(Element)->T) -> [Element] {
var uniqueKeys = Set<String>()
return filter{ uniqueKeys.insert("\(keyValue($0))").inserted }
}
I need to filter objectArray to obtain an array without duplicated objects with the condition to maintain the highest value for times property, that means, the final result should be:
Expected result:
filteredObjectArray = [
MyObject(name: “Obj1”, id: “123”, times: 1, value: 3.0),
MyObject(name: “Obj3”, id: “789”, times: 1, value: 1.0),
MyObject(name: “Obj2”, id: “456”, times: 3, value: 4.7),
MyObject(name: “Obj4”, id: “212”, times: 1, value: 2.4)
]
With Obj2 repeated item filtered by times property = 3
Here is a solution using reduce(into:) to filter out the unique objects
let uniqueAndHighest = objectArray.reduce(into: [MyObject]()) { array, object in
if let index = array.firstIndex(where: { $0.id == object.id }) {
if array[index].times < object.times {
array[index] = object
}
} else {
array.append(object)
}
}
and an alternative solution using Dictionary(grouping:)
let uniqueAndHighest = Dictionary(grouping: objectArray) {$0.id}
.values
.compactMap { $0.max {$0.times < $1.times}}
You can use reduce in this case:
let resultArray = objectArray.reduce([]) { (nextResult, obj) -> [MyObject] in
var tempArray = nextResult
if let existObj = tempArray.first(where: { $0.name == obj.name && $0.id == obj.id }) {
if obj.times > existObj.times {
tempArray.removeAll(where: { $0.name == existObj.name })
tempArray.append(obj)
}
} else {
tempArray.append(obj)
}
return tempArray
}

Protractor - How to check if object is contained in another object?

I have two objects:
let obj1 = {
FirstName: "John",
LastName: "Doe",
age: 20,
color: "Purple"
}
let obj2 = {
FirstName: "John",
LastName: "Doe",
color: "Purple
}
As you can see, I got two almost similar 2 objects.
The only difference is that the second object doesn't have "age" property in it.
I want to compare between them and check if the second object is "contained" in the first one.
I tried
expect(obj1).toContain(obj2);
It doesn't work.
Is that even possible option?
If the objects are the same you can use Equatable, for example:
struct Person: Equatable {
var name: String?
var color: UIColor?
var LastName: String?
}
var person1 = Person()
person1.name = "roei"
person1.LastName = "b"
person1.color = .blue
var person2 = Person()
person2.name = "roei"
person2.LastName = "b"
person2.color = .blue
if person1 == person2 {
print("good")
}
it will print good

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

Sorting Struct array in Swift 4

I've got the below struct and would like to sort the items within sessions by startTime field. I'm completely lost on how to do this.
I tried:
let sortedArray = sessionsData?.items.sorted{ ($0["startTime"] as! String) < ($1["startTime"] as! String) }
but that just gives me an error about no subscript members?
Any pointers would really be appreciated, thank you.
public struct sessions: Decodable {
let status: String?
let start: Int?
let count: Int?
let items: [sessionInfo]?
let itemsCount: Int?
let multipart: Bool?
let startTime: Int?
let endTime: Int?
}
public struct sessionInfo: Decodable {
let name: String?
let datalist: String?
let sessionType: Int?
let status: Int?
let backupType: Int?
let startTime: Int?
let endTime: Int?
let owner: String?
let numOfErrors: Int?
let numOfWarnings: Int?
let flags: Int?
}
I tried the below, but get an error:
var sortedArray = sessionsData?.items?.sorted(by: { (lhs, rhs) -> Bool in
return lhs.startTime < rhs.startTime
})
error:
Binary operator '<' cannot be applied to two 'Int?' operands
Try below code, it sorts the struct in asc order but it pushes nil timestamps to bottom.
if you want nil timestamps to be at top, make all nil checks in below code to return opposite of what i return in below code.
var sortedArray = sessionsData?.items?.sorted(by: { (lhs, rhs) -> Bool in
if let lhsTime = lhs.startTime, let rhsTime = rhs.startTime {
return lhs.startTime < rhs.startTime
}
if lhs.startTime == nil && rhs.startTime == nil {
// return true to stay at top
return false
}
if lhs.startTime == nil {
// return true to stay at top
return false
}
if rhs.startTime == nil {
// return false to stay at top
return true
}
})
You should access the fields directly and not through subscripts.
let sortedArray = sessionsData?.items.sorted(by: {$0.startTime < $1.startTime})
You could write this (tested in playground) :
var sortedArray = sessionsData?.items?.sorted(by: { (lhs, rhs) -> Bool in return (lhs.startTime ?? 0) < (rhs.startTime ?? 0) })
If one is optional, you do not crash, even though result of comparison is meaningless
You have default High Order Function for sorting the struct array in ascending and descending order
Example
let roster: [TeamMember] = [.init(id: 1, name: "Abishek", age: 19),
.init(id: 2, name: "Dinesh", age: 22),
.init(id: 3, name: "Praveen", age: 24),
.init(id: 4, name: "Sam", age: 25),
.init(id: 5, name: "David", age: 21)]
let descendingSorted = roster.sorted{$0.name > $1.name} // for descending order
let ascendingSorted = roster.sorted{$0.name < $1.name} // for ascending order
print(descendingSorted)
print(ascendingSorted)
Your Output
// for descending order
[TeamMember(id: 4, name: "Sam", age: 25.0),
TeamMember(id: 3, name: "Praveen", age: 24.0),
TeamMember(id: 2, name: "Dinesh", age: 22.0),
TeamMember(id: 5, name: "David", age: 21.0),
TeamMember(id: 1, name: "Abishek", age: 19.0)]
// for ascending order
[TeamMember(id: 1, name: "Abishek", age: 19.0),
TeamMember(id: 5, name: "David", age: 21.0),
TeamMember(id: 2, name: "Dinesh", age: 22.0),
TeamMember(id: 3, name: "Praveen", age: 24.0),
TeamMember(id: 4, name: "Sam", age: 25.0)]
And we have another one method for sorting is SortComparator. we sort the result based on ComparisonResult
let descendingSorted1 = roster.sorted { teamMember1, teamMember2 in
return teamMember1.name.compare(teamMember2.name) == .orderedDescending
} // for descending order
let ascendingSorted1 = roster.sorted{ teamMember1, teamMember2 in
return teamMember1.name.compare(teamMember2.name) == .orderedAscending
} // for ascending order
print(descendingSorted1)
print(ascendingSorted1)

Resources