FlatDog
FlatDog

Reputation: 2733

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

Upvotes: 3

Views: 3798

Answers (4)

Abishek Thangaraj
Abishek Thangaraj

Reputation: 923

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)

Upvotes: 0

Karthik Kumar
Karthik Kumar

Reputation: 1385

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
}

})

Upvotes: 4

claude31
claude31

Reputation: 884

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

Upvotes: 1

Palle
Palle

Reputation: 12109

You should access the fields directly and not through subscripts.

let sortedArray = sessionsData?.items.sorted(by: {$0.startTime < $1.startTime})

Upvotes: 2

Related Questions