Holy Swift

Holy Swift

Using tuples to Complex Sorting Operations in Swift

Using tuples to Complex Sorting Operations in Swift

Subscribe to my newsletter and never miss my upcoming articles

Hallo mannen en vrouwen, Leo hier.

Today we will explore some sorting possibility using tuples. Sorting operation is pretty straightforward in Swift and can be used automatically with types that conforms to comparable.

Sorting operations are very important to show data the way we want, so if the data isn't in the right order we can easily fix that with the the sorting operation. And even the typo don't conform to comparable protocol, we can use a custom sorting closure to rearrange the data.

Fasten your seatbelts and prepare to code! But first...

The Painting

A Trip to the Moon (French: Le Voyage dans la Lune) is a 1902 French adventure short film directed by Georges Méliès. This is drawing by Georges Méliès of the vessel landing in the moon's eye in the film Le voyage dans la lune. This film was inspired by a wide variety of sources, including Jules Verne's 1865 novel From the Earth to the Moon and its 1870 sequel Around the Moon, the film follows a group of astronomers who travel to the Moon in a cannon-propelled capsule, explore the Moon's surface, escape from an underground group of Selenites (lunar inhabitants), and return to Earth with a captive Selenite.

I choose this drawing because of the Movie struct example that I used. And this is a very very old movie (1902) with a drawing made by the director himself, pretty unusual isn't it?

The Problem

You want to sort a list of movies by the title, year and director.

First of all open your favorite Xcode's Playground file and type this:

struct Movie {
    let title: String
    let year: Int
    let director: String
}

let movieList = [
    Movie(title: "Star Wars", year: 1898, director: "Leorge Mucas"),
    Movie(title: "A Star", year: 1922, director: "Michal Platpus"),
    Movie(title: "Be yourself", year: 1700, director: "Coey Vamn"),
    Movie(title: "The big bang", year: 2011, director: "Rom Natas"),
    Movie(title: "The big bang", year: 1922, director: "Adra Kngr"),
    Movie(title: "Finding Nemoy", year: 2022, director: "Raxip"),
    Movie(title: "The big bang", year: 2011, director: "Jos Klimbr")
]

Nothing fancy until now. Now let's sort the data based on title ascending:

let sortedMovieList = movieList.sorted { // Mark 1
     $0.title < $1.title
}

for movie in sortedMovieList {
    print(movie)
}

The sorting function we are using is from Swift Array, it receives a closure with two parameters to know how it can compare two types (in this case two movies).

In Mark 1 we are taking advantage of trailing closures and implicitly parameters to compare two Strings and return a Boolean value that represents the comparison between the two movies:

Screen Shot 2021-07-07 at 11.28.26.png

You should see this result in console:

Screen Shot 2021-07-07 at 11.11.52.png

Cool! That worked as we planned.

But what if we want to the movie "The Big Bang" be sorted with the year too? As you can see in the image above the title are sorte but the year is not. You can do this to fix:

let sortedMovieList = movieList.sorted {
    if $0.title == $1.title { // Mark 1
        return $0.year < $1.year // Mark 2
    }
    return $0.title < $1.title // Mark 3
}

for movie in sortedMovieList {
    print(movie)
}

This start to be a little confusing but it still ok...

The Mark 1 are saying: If the names are equal, please use another variable to compare. And the Mark 2 is the other variable we use to compare, in this case the year. The Mark 3 is used when the movie title aren't equal so the comparison is just the title.

Screen Shot 2021-07-07 at 11.43.52.png

The result above demonstrates that our closure is working fine. All the films are sorted ascending by the title and films with equal names they are sorted by their year.

Let's complicate a little more. In the image above you can see that films with the same name and the same year can have different directors( Hollywood can't stop!), so it would be awesome to sort the director attribute in ascending order too. We can rearrange that too!

Let's write some more code to accomplish this new feature:

let sortedMovieList = movieList.sorted {
    if $0.title == $1.title {
        if $0.year == $1.year {
            return $0.director < $1.director
        }
        return $0.year < $1.year
    }
    return $0.title < $1.title
}

for movie in sortedMovieList {
    print(movie)
}

Resulting in this:

Screen Shot 2021-07-07 at 11.51.09.png

The algorithm is the same and you can imagine if we had a really big struct how confusing would be to maintain a code like this. This is starting to be a pyramid of doom so we have to do something. Here is where the tuples save the day!

The Tuple Solution

Tuples comparison are great to do what we want here. Just put every property that you want to compare inside the tuple and it's done:

let sortedMovieList = movieList.sorted {
    ($0.title, $0.year, $0.director) < ($1.title, $1.year, $1.director)
}

for movie in sortedMovieList {
    print(movie)
}

This way you can sort you data by title, year and finally director with ease of use syntax. Swift is awesome, isn't it?

And another perk is that if you want to sort by the year, title and director, in this order you can just change the position inside the tuple:

let sortedMovieList = movieList.sorted {
    ($0.year, $0.title, $0.director) < ($1.year, $1.title, $1.director)
}

for movie in sortedMovieList {
    print(movie)
}

Resulting:

Screen Shot 2021-07-07 at 11.55.41.png

One Descending Element

You may be thinking: What if I wanted to only the year be descending, and the rest be ascending?

Just change the $0 with the $1 parameter and you can achieve that. Check the code below:

let sortedMovieList = movieList.sorted {
    ($0.title, $1.year, $0.director) < ($1.title, $0.year, $1.director)
}

for movie in sortedMovieList {
    print(movie)
}

Now the result is:

Screen Shot 2021-07-07 at 11.58.03.png

Check the movie "The Big Bang" is now with the years in descending order instead of ascending, but the director is still ascending.

Conclusion

That's all my people, I hope you liked this as I liked writing. If you want to support this blog you can Buy Me a Coffee or just leave a comment saying hello.

Thanks for the reading and... That's all folks.

credits: image

Interested in reading more such articles from Leonardo Maia Pugliese?

Support the author by donating an amount of your choice.

#swift#ios#apple#algorithms
 
Share this