1

Looking to sort an array

var myArray = ["Dog", "B-1", "C-1", "C-2", "C-3","Home"]

in an given characters string order.

e.g.: where myCustomString = "DC"

Input Array:

["Dog","Goat","C-1","C-2","C-3","Home"]

Expected Output Array:

["Dog", "C-1".."C-3","B-1","Home"] // sorted by myCustomString variable 
Code Different
  • 90,614
  • 16
  • 144
  • 163
Nick
  • 1,127
  • 2
  • 15
  • 40

2 Answers2

3

If will be easier if you convert myCustomString into an array of characters. Working with Swift's String is a bit of a pain the neck since the subscripting API is so clumsy. Here's one way to do it:

Swift 3:

var myArray = ["Dog", "B-1", "C-1", "C-2", "C-3","Home"]
let myCustomString = "DC".characters.map { $0 }

myArray.sort { str1, str2 in
    let index1 = str1.isEmpty ? nil : myCustomString.index(of: str1[str1.startIndex])
    let index2 = str2.isEmpty ? nil : myCustomString.index(of: str2[str2.startIndex])

    switch (index1, index2) {
    case (nil, nil):
        return str1.compare(str2, options: .numeric) == .orderedAscending
    case (nil, _):
        return false
    case (_, nil):
        return true
    default:
        if index1 != index2 {
            return index1! < index2!
        } else {
            return str1.compare(str2, options: .numeric) == .orderedAscending
        }
    }
}

print(myArray)

Original answer:

  • Split myArray into 2 subarrays: one containing all the elements you have an order for; and one for elements that you do not
  • Sort subArray1 according to the order you specified
  • Sort subarray2 alphabetically
  • Concatenate subArray1 and subArray2 to make the new myArray

Example:

let myOrder = "DC".characters.map { $0 }
var myArray = ["Dog", "B-1", "C-1", "C-2", "C-3", "Home"]
var subArray1 = [String]()
var subArray2 = [String]()

myArray.forEach {
    if $0.isEmpty || !myOrder.contains($0[$0.startIndex]) {
        subArray2.append($0)
    } else {
        subArray1.append($0)
    }
}

subArray1.sort { str1, str2 in
    let firstChar1 = str1[str1.startIndex]
    let firstChar2 = str2[str2.startIndex]

    let index1 = myOrder.index(of: firstChar1)!
    let index2 = myOrder.index(of: firstChar2)!

    if index1 != index2 {
        return index1 < index2
    } else {
        return str1.compare(str2, options: .numeric) == .orderedAscending
    }
}

subArray2.sort { $0.compare($1, options: .numeric) == .orderedAscending }

myArray = subArray1 + subArray2

print(myArray)
Code Different
  • 90,614
  • 16
  • 144
  • 163
1

1) Split the "myCustomString" into its character components

2) Loop the array adding the words that start with the previously splitted character into its own array. So for this example you would end up with 3 arrays, one with strings starting with 'D', one with those starting with 'C' and anything else that didn't satisfy those 2 conditions.

  • Make a dictionary of arrays (String : [String]), in where the 'keys' are the previously obtained single characters (Like 'D', 'C', etc)

  • Make an extra array to hold those that didn't match any

  • Then loop through the input array looping the dictionary at the same time to see if the current string starts with the character from the key. If it didn't match any of the keys, place it inside the extra array.

3) Sort each array individually

4) Append the arrays back into 1

Community
  • 1
  • 1
Pochi
  • 13,391
  • 3
  • 64
  • 104