I have one array that defines an order,
let orderSettingArray = ["Admiral", "Captain", "Lieutenant"]
and another array with a few of these values
var myArray = ["Lieutenant", "Captain"]
I want to sort myArray
to reflect the order of orderSettingArray
:
var myArraySorted = myArray.getSorted(by: orderSettingArray)
Now print(myArraySorted)
should print ["Captain", "Lieutenant"]
-
Military ranks are one of the ideal use cases for enums. You should take advantage of that.Alexander– Alexander2017年05月17日 07:27:33 +00:00Commented May 17, 2017 at 7:27
-
1@NiravD: You are right (and I should have known about that one :) – This question is a tiny bit more general because it asks for an array extension method, but the underlying ideas are the same. Let's wait for more opinions whether to close this as a duplicate or not.Martin R– Martin R2017年05月17日 07:53:29 +00:00Commented May 17, 2017 at 7:53
-
@MartinR I know that's why I added duplicates question as just suggestionNirav D– Nirav D2017年05月17日 07:59:04 +00:00Commented May 17, 2017 at 7:59
-
The military ranks are just an example. The real scenario has customizable strings. @AlexanderJOG– JOG2017年05月17日 20:23:37 +00:00Commented May 17, 2017 at 20:23
4 Answers 4
So Easy let new = orderSettingArray.filter{ return myArray.contains(0ドル) }
Map each array element to a
(element, index)
tuple, where the index is the index of the array element in the order array. In your example that would be[("Lieutenant", 2), ("Captain", 1)]
Sort the array of tuples by the second tuple element (the index). In your case
[("Captain", 1), ("Lieutenant", 2)]
Extract the array elements from the sorted tuples array. In your case
["Captain", "Lieutenant"]
Code (for any array of equatable elements, not restricted to arrays of strings):
extension Array where Element: Equatable {
func getSorted(by orderArray: [Element]) -> [Element] {
return self.map { (0,ドル orderArray.index(of: 0ドル) ?? Int.max) }
.sorted(by: { 0ドル.1 < 1ドル.1 })
.map { 0ドル.0 }
}
}
let orderSettingArray = ["Admiral", "Captain", "Lieutenant"]
let myArray = ["Lieutenant", "Captain"]
let myArraySorted = myArray.getSorted(by: orderSettingArray)
print(myArraySorted) // ["Captain", "Lieutenant"]
Elements in myArray
which are not present in orderSettingArray
are assigned the index Int.max
and therefore sorted to the end
of the result.
-
Hello, Don't you think that this answer is even simpler? and it should be applicable for any array of equatable elements, not restricted to arrays of strings...Ahmad F– Ahmad F2017年05月17日 06:59:30 +00:00Commented May 17, 2017 at 6:59
-
@AhmadF: The difference is that it won't handle repeated elements in
myArray
, or elements inmyArray
which are not inorderSettingArray
. If that is not an issue, the solution is fine.Martin R– Martin R2017年05月17日 07:02:15 +00:00Commented May 17, 2017 at 7:02
Update
I've found a better design for this. It has quite a few improvements:
- I use a
Dictionary
to speed up ordering look-ups - By extracting this behaviour into a separate type, the dictionary can be cached and reused between multiple sorts
- The ordering-derivation is decoupled from sorting, so it could be used in more ways
- The
omitEntirely
responsibility was removed entirely. It should instead by done by a simple call tofilter
, withhardcodedOrdering.contains
as the predicate.
-
Wow, such a great exhaustive answer.JOG– JOG2017年05月17日 20:28:11 +00:00Commented May 17, 2017 at 20:28
-
@JOG yeah, it's an operation I've had to do several times, so I've spent quite a some time building and refining thisAlexander– Alexander2017年08月11日 05:19:52 +00:00Commented Aug 11, 2017 at 5:19
Swift 3
extension Array where Element: Hashable {
func getSorted(by: Array<String>) -> Array<String> {
var d = Dictionary<Int, String>()
for value in self {
for i in 0 ..< by.count {
if value as! String == by[i] {
d[i] = value as? String
}
}
}
var sortedValues = Array<String>()
for key in d.keys.sorted(by: <) {
sortedValues.append(d[key]!)
}
return sortedValues
}
}
-
Note that this is only functional for
[String]
Ahmad F– Ahmad F2017年05月17日 06:50:28 +00:00Commented May 17, 2017 at 6:50 -
4Oh boy, this is unnecessarily complex.Alexander– Alexander2017年05月17日 06:55:24 +00:00Commented May 17, 2017 at 6:55
-
1Not optimal, sure. Complex, nah. :)JOG– JOG2017年05月17日 20:35:03 +00:00Commented May 17, 2017 at 20:35