0

I am trying to use a NSMutableOrderedSet to store some data, but I would like to sort the set by a specific attribute. I tried to look online on how to use the sort(comparator cmptr: (Any, Any) -> ComparisonResult) function of the NSMutableOrderedSet but I am unsure on how to use this. I would like to know if someone could give me a quick example I was unable to find any tutorials or examples on Apples developer documentation.

Currently I have:

jersey.swift:

    struct Jersey{
       var name: String
       var number: Int
}

viewcontroller.swift:

let firstBasemanJersey = Jersey(name: "Bob", number: 5)
let secondBasemanJersey = Jersey(name: "Jim", number: 15)
let thirdBasemanJersey = Jersey(name: "Jon", number: 1)
let catcherJersey = Jersey(name: "Steve", number: 79)

var jerseySet = NSMutableOrderedSet()
jerseySet.addObject(firstBasemanJersey)
jerseySet.addObject(secondBasemanJersey)
jerseySet.addObject(thirdBasemanJersey)
jerseySet.addObject(catcherJersey)

I would like to sort the set by the jersey.number would someone be able to show me how would I use the

self.something.sort { (<#Any#>, <#Any#>) -> ComparisonResult in
            <#code#>
        }
Ace
  • 603
  • 2
  • 15
  • 33
  • Since `OrderedSet` is using `Any` as element type, it's not a good structure to be used in Swift. Also note that you should start by declaring `Jersey` to be `Hashable`, otherwise the `Set` part of `OrderedSet` won't really work (that is, the `contains` method won't work and you will be able to insert the same object multiple times). – Sulthan Mar 07 '20 at 22:58
  • @Sulthan I totally agree with that. I was on the fence about providing an answer but did so only for helping clarifying the use of the api. – Alladinian Mar 07 '20 at 23:01
  • @Alladinian The real usage for an `OrderedSet` is to have a combination of a `Set` and an `Array`, where all operations are automatically performed on both substructures. For example, `add` does not happen if `Set` already contains the item. If the ultimate aim is to sort the items, there is no need to keep items ordered while updating. Instead of an `OrderedSet`, I would probably create my own Swift generic struct doing the same. – Sulthan Mar 07 '20 at 23:27
  • @Sulthan Once again, fully agree... hence the second part of my answer. Having said that, I tried to make as little assumptions as possible about the intentions of the OP. What if this is for a UI that adds unique items in a list and there is a button to let you sort them (in place) by number for example? That would be a valid case for an ordered set & a (possible) sort. If we got more details about the use of this code then a more insightful answer on this would be more appropriate, I agree. – Alladinian Mar 07 '20 at 23:43

1 Answers1

0

In the most basic form you just have to compare the two arguments (a pair of Any objects since the Set doesn't 'know' what objects is currently holding) and return a ComparisonResult that can be either orderedAscending, orderedDescending or orderedSame:

jerseySet.sort(comparator: { lhs, rhs in
    guard let (l, r) = (lhs, rhs) as? (Jersey, Jersey) else { return .orderedSame }
    guard l.number != r.number else { return .orderedSame }
    return l.number < r.number  ? .orderedAscending : .orderedDescending
}) 

now if you print(jerseySet.array):

[Jerseys.Jersey(name: "Jon", number: 1), Jerseys.Jersey(name: "Bob", number: 5), Jerseys.Jersey(name: "Jim", number: 15), Jerseys.Jersey(name: "Steve", number: 79)]

And (for the reasons mentioned in the question comments) here is a "Swiftier" version of this:

struct Jersey: Hashable {
   let name: String
   let number: Int
}

let firstBasemanJersey  = Jersey(name: "Bob", number: 5)
let secondBasemanJersey = Jersey(name: "Jim", number: 15)
let thirdBasemanJersey  = Jersey(name: "Jon", number: 1)
let catcherJersey       = Jersey(name: "Steve", number: 79)

// Kept as var assuming that you will later `.insert` things in the set
var jerseySet = Set([
    firstBasemanJersey,
    secondBasemanJersey,
    thirdBasemanJersey,
    catcherJersey
])

let sortedByNumber = jerseySet.sorted { lhs, rhs in
    lhs.number < rhs.number
}
Alladinian
  • 34,483
  • 6
  • 89
  • 91