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 

2 Answers 2

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)
Sign up to request clarification or add additional context in comments.

Comments

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

2 Comments

Can you give me an example?
I wrote a more detailed explanation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.