2

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"]

Ahmad F
31.8k19 gold badges100 silver badges150 bronze badges
asked May 17, 2017 at 6:25
4
  • Military ranks are one of the ideal use cases for enums. You should take advantage of that. Commented 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. Commented May 17, 2017 at 7:53
  • @MartinR I know​ that's why I added duplicates question as just suggestion Commented May 17, 2017 at 7:59
  • The military ranks are just an example. The real scenario has customizable strings. @Alexander Commented May 17, 2017 at 20:23

4 Answers 4

6

So Easy let new = orderSettingArray.filter{ return myArray.contains(0ドル) }

answered May 17, 2017 at 6:42
2
  • 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.

answered May 17, 2017 at 6:53
2
  • 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... Commented May 17, 2017 at 6:59
  • @AhmadF: The difference is that it won't handle repeated elements in myArray, or elements in myArray which are not in orderSettingArray. If that is not an issue, the solution is fine. Commented May 17, 2017 at 7:02
1

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 to filter, with hardcodedOrdering.contains as the predicate.

See my new answer, here

answered May 17, 2017 at 7:16
2
  • Wow, such a great exhaustive answer. Commented 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 this Commented Aug 11, 2017 at 5:19
1

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
 }
}
Ahmad F
31.8k19 gold badges100 silver badges150 bronze badges
answered May 17, 2017 at 6:25
3
  • Note that this is only functional for [String] Commented May 17, 2017 at 6:50
  • 4
    Oh boy, this is unnecessarily complex. Commented May 17, 2017 at 6:55
  • 1
    Not optimal, sure. Complex, nah. :) Commented May 17, 2017 at 20:35

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.