0

I have a list of string:

var nameList = ["Apple", "Watermelon", "orange", ...]

The list is returned from backend, order not garanteed.

I only want to have orange to always be the 1st element in array, no need to care the other elements' order.

I try to use nameList.sort { $0 // what to do}, but get stuck, because I only want one element to be the first element.

How to achieve it?

====== UPDATE ======

A followup question. If I have a list of fruit objects, each fruit is a custom struct object:

struct Fruit {
  public let name;
  public let weight;

  init(_ name: String, _ weight: Double) {
     self.name = name
     self.weight = weight
  }

}

Now, I got a list of Fruit:

var fruitList:[Fruit] = getDataFromBackend()

I would like to have the fruit with name "orange" always be the first item, how to do now?

Leem.fin
  • 40,781
  • 83
  • 202
  • 354

5 Answers5

3

You can find the index of "orange", and swap it into 0-th index:

if let indexOfOrange = nameList.index(of: "orange") {
    if indexOfOrange != 0 {
        swap(&nameList[0], &nameList[indexOfOrange])
    }
}

If the list can have multiple oranges, use this snippet instead:

let sorted = nameList.filter {$0 == "orange"} + nameList.filter {$0 != "orange"}

It concatenates a list of all oranges with the list of all non-oranges.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Perfect one :) Hence +1 – Sandeep Bhandari Sep 11 '17 at 11:05
  • Note that `swap` does not swap a value with itself, you'll have to check if indexOfOrange is not zero. – Martin R Sep 11 '17 at 11:05
  • @MartinR Thank you for the comment! I did not realize there was a restriction on this. – Sergey Kalinichenko Sep 11 '17 at 11:08
  • 1
    That's why there are all the `guard i != j` statements in the Swift 2/3 versions in https://stackoverflow.com/a/24029847/1187415. The Swift 4 `swapAt()` collection method does not have this restriction anymore. – Martin R Sep 11 '17 at 11:10
  • I have a followup question, could you please check my update in my question? Thanks. – Leem.fin Sep 11 '17 at 11:56
  • @Leem.fin: If you lookup `index(of:)` in https://developer.apple.com/documentation/swift/array then you should notice that there is a related `index(where:)` method ... – Martin R Sep 11 '17 at 12:10
1

A slight variation of dasblinkenlight's solution: Move the "orange" element (if present) to the front and preserve the order of the remaining elements:

var nameList = ["Apple", "Watermelon", "orange"]

if let idx = nameList.index(of: "orange"), idx != 0 {
    nameList.insert(nameList.remove(at: idx), at: 0)
}

print(nameList) // ["orange", "Apple", "Watermelon"]
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
0

Well, if order of other elements doesn't matter, you can sort like this:

var nameList = ["Apple", "Watermelon", "orange"]
print(nameList.sorted(by: { first, _ in first == "orange" })) // ["orange", "Apple", "Watermelon"] 

In this case we set the first element what we need ("orange") and don't care about others.

pacification
  • 5,838
  • 4
  • 29
  • 51
0

I don't know is it the perfect solution for your question or not but you can try using this. It works for me:-

 let nameList : NSMutableArray = (["Apple", "Watermelon", "orange"] as NSArray).mutableCopy() as! NSMutableArray

    if nameList.contains("orange") {
        nameList.remove("orange")
        nameList.insert("orange", at: 0)
    }
Rushita
  • 11
  • 4
0

Here's a very simple way to use the native sort function for this:

var fruitList = ["Apple", "Watermelon", "orange"]

let orangeFirst = fruitList.sorted{$1 != "orange"}

orangeFirst // ["orange", "Watermelon", "Apple"]

The function you pass to sorted() is expected to response with true if the first parameter goes before the second one. So any value that is not "orange" should go after orange.

Note that if I had used $0 == "orange" the compiler would have complained that it wanted a two parameter function. By using $1 instead, it understands that there is implicitly a $0 and a $1.

Alain T.
  • 40,517
  • 4
  • 31
  • 51
  • This is not a valid "strict weak ordering" because "x less than x" evaluates to true for any string x != "orange". – Martin R Sep 12 '17 at 07:41
  • This would only be relevant if there were duplicates in the data set. While I agree that the poster should be aware of this limitation, it should be expressed in such a way that its impact is conveyed rather than merely stating the theoretical foundation. – Alain T. Sep 12 '17 at 10:44
  • The [`sorted(by:)`](https://developer.apple.com/documentation/swift/array/2296815-sorted) methods expects the predicate to be a strict weak order, as documented. In particular, it must be irreflexive (areInIncreasingOrder(a, a) is always false). – I have no idea what happens if this requirement is violated (as in your code), it may work or not. – Martin R Sep 12 '17 at 11:13
  • Depending on the underlying implementation, the presence of multiple "orange" elements way cause infinite loops or inconsistent sort results. There are however no sort algorithm (that I know of) that would need to compare a specific element to itself. Bubble, Insertion, Selection, Merge, Tree and (most likely here) Knut's QuickSort all perform comparisons between distinct elements. So, when there are no duplicate "orange" elements, this "invalid" function will produce the expected result because "orange" will never actually be compared to "orange". – Alain T. Sep 12 '17 at 20:26
  • Actually it is insertion sort. – But why rely on specific behaviour if it easy to pass a *valid* predicate: `{$0 == "orange" && $1 != "orange"}` – Martin R Sep 13 '17 at 09:20
  • Agreed, it was just a matter of conciseness. And in that same spirit, using a sort O(n^2) to displace a single element (which can be done in O(n) time) is also a bit of a side step. I merely pushed it a little bit farther. Just to be clear, I think the solution you (Martin R.) proposed is much better. – Alain T. Sep 13 '17 at 12:14