Sorting Array in Swift3

32,307

Solution 1

If you want to sort alphabetically and then numerically, you can:

var array = ["A2", "B7", "A4", "C3", "A1", "A10"]
array.sort { $0.compare($1, options: .numeric) == .orderedAscending }

That produces:

["A1", "A2", "A4", "A10", "B7", "C3"]

I added A10 to your array, because without it, a simple alphabetic sort would have been sufficient. But I'm assuming you wanted A10 after A4, in which case the numeric comparison will do the job for you.


You changed the example to be a struct with two properties. In that case, you can do something like:

struct Foo {
    var name: String
    var count: Int
}

var array = [
    Foo(name:"A", count: 2),
    Foo(name:"B", count: 7),
    Foo(name:"A", count: 7),
    Foo(name:"C", count: 3),
    Foo(name:"A", count: 1),
    Foo(name:"A", count: 10)
]

array.sort { (object1, object2) -> Bool in
    if object1.name == object2.name {
        return object1.count < object2.count
    } else {
        return object1.name < object2.name
    }
}

Or, more concisely:

array.sort { $0.name == $1.name ? $0.count < $1.count : $0.name < $1.name }

Or

array.sort { ($0.name, $0.count) < ($1.name, $1.count) }

Note, rather than putting this logic in the closure, I'd actually make Foo conform to Comparable:

struct Foo {
    var name: String
    var count: Int
}

extension Foo: Equatable {
    static func ==(lhs: Foo, rhs: Foo) -> Bool {
        return (lhs.name, lhs.count) == (rhs.name, rhs.count)
    }
}

extension Foo: Comparable {
    static func <(lhs: Foo, rhs: Foo) -> Bool {
        return (lhs.name, lhs.count) < (rhs.name, rhs.count)
    }
}

This keeps the comparison logic nicely encapsulated within the Foo type, where it belongs.

Then you can just do the following to sort in place:

var array = ...
array.sort()

Or, alternatively, you can return a new array if you don't want to sort the original one in place:

let array = ...
let sortedArray = array.sorted()

Solution 2

Narusan, maybe this will help you. Let's say you have an array with your struct objects called objArray, then you can order it by the code bellow:

var objArray = [Object]()
objArray.append(Object(name:"Steve", count:0))
objArray.append(Object(name:"Alex", count:1))

objNameSorted = objArray.sorted (by: {$0.name < $1.name})
objNCountSorted = objArray.sorted (by: {$0.count < $1.count})

Solution 3

You can still use shorthand for sorted:

objNameSorted = objArray.sorted { $0 < $1 }

While less readable, it more closely mimics the sort syntax.

Share:
32,307
Narusan
Author by

Narusan

Feel free to check out the new site proposal MedicalSciences.SE Ping me in the Waiting Room or Listening to Blips of the Heart!

Updated on June 09, 2020

Comments

  • Narusan
    Narusan almost 4 years

    In my code, I have a struct like the following:

    struct Object {
        var name: String
        var count: Int
    

    I am now creating an array of 10 Objects with random names and random counts.

    Is there an easy way to
    a) sort them alphabetically
    b) sort them numerically in ascending order

    Basically, there will be an array like so: [Object1, Object2, Object3]. Every Object has a name and count attribute, and I want the objects in that list be sorted via these two attributes.

    Solution in Swift2 (using this solution: StackOverflow):

    Object.sort{
            if $0.name != $1.name {
                return $0.name < $1.name
            }
            else {
                //suits are the same
                return $0.count < $1.count
            }
        }
    

    However, this has been renamed to sorted(by: ) in Swift3, and I don't quit get how to do that.

  • Rob
    Rob over 7 years
    No, in Swift 3, sorted is the version that returns a new array. sort is the version that sorts in place.
  • Rob
    Rob over 7 years
    Then you must not be sorting in place, but rather trying to return it as a new array, in which case you'd do let sortedArray = array.sorted() { ... }.
  • Narusan
    Narusan over 7 years
    Sorry that I can't do anything more than up vote your answer and comments, you deserve way more!
  • mfaani
    mfaani over 7 years
    why did you write static func?
  • Rob
    Rob over 7 years
    In Swift 2, the equality and comparison operators were implemented as globals, but in Swift 3 they are defined as static methods of the type, which keeps your code a little better organized. See Improving operators in protocols.
  • mfaani
    mfaani over 7 years
    correct me if I'm wrong, you can still do it the Swift2 way in Swift 3, ie define it as a global func ? However it's not recommended?
  • Rob
    Rob over 7 years
    It's a poor design, IMHO, but, yes, you can do it the old way, too.
  • kakubei
    kakubei almost 7 years
    You can still use shorthand for sorted: objNameSorted = objArray.sorted { $0 < $1 } While less readable, it more closely mimics the sort syntax.