0

I need something like the following:

let arr = [...] //array of strings
let resultArr = arr.sort({obj1,obj2 in
   if some_condition(obj1, obj2) {
     ...//return the order of obj1 and obj2 from arr
   } else {
     return obj1 < obj2
   }
})

I saw a lot of questions/answers how to simply sort the array items but no one answers how to store the original order. some_condition may be any but each array object may be sorted with the original order or with the new one. How to solve this issue?

Example

let arr = ["a", "f", "d", "b", "y", "c", "e"]
//elements "a", "d", "f" conform some_condition
resultArr == ["a", "f", "d", "b", "c", "e", "y"]
Machavity
  • 30,841
  • 27
  • 92
  • 100
Vyachaslav Gerchicov
  • 2,317
  • 3
  • 23
  • 49
  • You are looking for « stable sorting »: https://stackoverflow.com/questions/40673374/how-to-stable-sort-an-array-in-swift ? – Larme Oct 05 '17 at 08:29
  • *"each array object may be sorted with the original order or with the new one"* is unclear to me. Perhaps you can add an example which clearly demonstrates your problem? – Martin R Oct 05 '17 at 08:45
  • 1
    @MartinR @Larme No. That question is about `A nonstable sort may change the relative order of elements that compare equal.` Added an example – Vyachaslav Gerchicov Oct 05 '17 at 08:46
  • "how to store the original order" Made me thought that you wanted a "stable sort" question was either unclear and/or misunderstood by me. You meant like in pseudo code `let except = ["a", "d", "f"] if (except.contains(obj1) && !except.contains(obj2){ return true} else if (!except.contains(obj1) && except.contains(obj2){ return false} else{ return obj1< obj2 }`? – Larme Oct 05 '17 at 08:51
  • I see the alphabetical order sort, but what if `let arr = ["a", "f", "d", "b", "y", "c", "e"]`, does `resultArr == ["a", "f", "d", "b", "c", "e", "y"]` or `resultArr == ["a", "d", "f", "b", "c", "e", "y"]`? If it's the first one, stable sort should be the solution (except if there is another special order), for the last one, just read my pseudo code in previous comment. – Larme Oct 05 '17 at 08:55
  • Is some_condition a *predicate* which takes a single element as argument, or a *relation* between two elements (as `some_condition(obj1, obj2)` in your question implies=? – How should elements satisfying the predicate should be sorted relative to elements not satisfying the predicate? – Martin R Oct 05 '17 at 08:56
  • @Larme fixed. The idea is to store these some elements in the same order (not only ascending/descending) – Vyachaslav Gerchicov Oct 05 '17 at 13:18
  • @MartinR wrote `some_condition(obj1, obj2)` just because `sort` has 2 parameters inside to compare. Maybe the following description will be more clear. `The initial array consists of elements, each belong to one from 2 sets. What if I want to sort the elements from the first set and leave the second set as is? Of course the elements from the first set can change their positions and positions for elements from the 2nd set are fixed.` – Vyachaslav Gerchicov Oct 05 '17 at 13:32

1 Answers1

1

If I understand correctly, the elements that meet your condition need to stay exactly in their original positions and the other ones will be reordered within the positions that are not fixed.

What you could do is map the original indexes of the sortable entries to the sorted subset of their values. Then use that pairing to reassign only the array's elements that are eligible to sorting with their respective (reordered) values.

For example:

var arr = ["a", "f", "d", "b", "y", "c", "e"]

let isFixed:(String)->Bool = { ["a","f","d"].contains($0) } // condition for fixed elements

zip(arr.enumerated().filter{!isFixed($1)},arr.filter{!isFixed($0)}.sorted())
.forEach{ arr[$0.0] = $1 }

print(arr) // ["a", "f", "d", "b", "c", "e", "y"]
Alain T.
  • 40,517
  • 4
  • 31
  • 51
  • Nice solution. The key point is that the desired order cannot be achieved directly by the library sort functions; as the order of any two elements depends on their relative positions, and that changes during the sort, which in turn breaks the library sort contract. You either have to write a custom sort or separate the original data into fixed and movable sets, use a library sort of the latter, and recombine. You've a nice formulation of the spilt/recombine approach. – CRD Oct 05 '17 at 20:09
  • didn't checked if it is correct yet but you should fix your answer: 1)no "afd" string exist - I use array of strings instead and each string may have any length > 0; 2)will it work if I fix strings "ady" for example? – Vyachaslav Gerchicov Oct 06 '17 at 08:25
  • The condition was merely an example. Since it is an arbitrary function, it could be anything so yes this will also work for other combinations such as "ady". – Alain T. Oct 06 '17 at 11:58