Today’s challenge is courtesy of the Swift Users email list, posted by Adriano Ferreira. His starting point is here, where he was really looking to simplify chained calls. But making things Swifter isn’t always just about making chaining look better.
func selectionSort(_ array: [Int]) -> [Int] { guard array.count > 1, let minElement = array.min() else { return array } let indexOfMinElement = array.index(of: minElement)! // All of this just to filter out the first smallest element and return the rest // Also tried ‘suffix(from:)' here, but couldn’t make it work properly let rest = array.enumerated() .filter({ index, _ in index != indexOfMinElement }) .map({ _, element in element }) return [minElement] + selectionSort(rest) }
What can make this Swifter?
First, practicality. Even though any array of 0 or 1 elements is already sorted, I don’t think adding code to test for those conditions is practical. I think it’s better just to streamline and let the code run, even if the case of one element isn’t perfectly ideal.
Second, flow. I don’t like the idea of first finding the minimum and then finding its index. Enumeration allows these operations to be run in tandem.
Third, style. Enumeration should really return (index: Index, value: Element) tuples. It doesn’t. So I took this opportunity to extend Array to create the kind of tuples I’d rather work with. Because of that, my solution is more complex than it really needs to be (for a sorting function no one ever actually uses) because I’d rather use code that handles $0.value
and $1.index
than $0.1
and $1.0
.
My redesigned code is here. Share yours!
@ericasadun Here's a purely functional version https://t.co/PGC05pPvzP
Not sure I made it better; it's kinda frightening.— Matt Gallagher (@cocoawithlove) June 29, 2016
guard array.count > 1 else { return array }
let (minElement,minIndex) = zip(array,array.indices).min {$0.0 < $1.0}!— AirspeedVelocity (@AirspeedSwift) June 29, 2016
@ericasadun not using the most recent Swift, but here’s my solution (in place): https://t.co/Uq0Y6rBWKK
— Andrew Bennett (@TheRealBnut) June 28, 2016
@ericasadun Fun! Here's my approach: https://t.co/W3gqoksbwu
— Dan Loewenherz (@dwlz) June 28, 2016
There's more here https://t.co/wKSI4eVUMz @ericasadun ? https://t.co/jv2u4RR5Lg
— Adriano Ferreira (@_adrfer) June 28, 2016
5 Comments
How about this? The generic constraints are murder, but I think the actual method itself is quite nice.
Beautiful! (Well, other than no spaces before and after `<` on the compare... 🙂 )
I’m horrified I missed that
Spaces before and after ..<, spaces after commas...
Today I learned about the maxSplits parameter of split, which led me to this implementation.