There're a few steps here. Firstly, sort requires you to adhere to a few assumptions:
areInIncreasingOrder must be a strict weak ordering over the elements. That is, for any elements a , b , and c , the following conditions must hold:
areInIncreasingOrder(a, a) is always false . (Irreflexivity)
- If
areInIncreasingOrder(a, b) and areInIncreasingOrder(b, c) are both true , then areInIncreasingOrder(a, c) is also true . (Transitive comparability)
- Two elements are incomparable if neither is ordered before the other according to the predicate. If
a and b are incomparable, and b and c are incomparable, then a and c are also incomparable. (Transitive incomparability)
Just like hash(into:), violating these requirements is generally a bug, and the result is undefined behaviour. Luckily always return false adhere to these rules, so the result is (relatively) defined. sort ensures that if areInIncreasingOrder(a, b) returns true, then a will precede b in the sorted list.
Now, what does it mean when areInIncreasingOrder always returns false? If areInIncreasingOrder(a, b) and areInIncreasingOrder(b, a) are both false, then it means that in a sorted list, a can be placed before or after b.
Is it required that the sorted list is in the exact same order? Not generally. If you sort [(1, "a"), (1, "b")] by the first member, then [(1, "b"), (1, "a")] is a perfectly valid result, 1 and 1 are next to each other in the sorted list, after all.
What you need is called "stable" sorts, where equal elements appear in the same order that it appears in the original list. Unfortunately, Array.sorted is apparently not stable.
The sorting algorithm is not guaranteed to be stable. A stable sort preserves the relative order of elements for which areInIncreasingOrder does not establish an order.
So what exactly is that order that the result returns? Well, that's an implementation detail. If it uses quicksort, it would be in one particular order and another order in merge sort. You see, many algorithms just assume that you can swap equal elements without problem (which is a pretty good optimization).
So if you want to make sure that "equal" elements appear in the same order that they appear, you need to encode it into the array somehow. One way is to add offset into the array before sorting, and strip it off afterward:
let ok = original.enumerated().sorted { false || $0.offset < $1.offset }.map { $0.element }
print(ok) // ["Kofi", "Abena", "Peter", "Kweku", "Akosua", "abena", "bee", "ábenā"]