0

I have an Array containing values like 7-4.json, 87-1.json and 102-4.json and want to sort it (ascending). I used the following code:

var fileNames = ["7-4.json", "87-1.json", "102-4.json"]
fileNames = fileNames.sort{ $0 < $1 }
print(fileNames)

which results in:

["102-4.json", "7-4.json", "87-1.json"]

So it didn't worked as I aspected. How can I sort it like 7-4, 87-1, 102-4?

3
  • 1
    You are going to need a custom sorting function for situations like this to deal with your specific string format. Commented Oct 12, 2015 at 15:36
  • 1
    Just so you know why it's doing this: it is sorting them as strings, not numbers and so is sorting on a character by character basis. Commented Oct 12, 2015 at 15:57
  • let array2 = array.sort { $0.compare($1, options: .NumericSearch) == .OrderedAscending } did the job for me Commented Oct 14, 2015 at 8:10

3 Answers 3

4

Here you go:

var fileNames = ["7-4.json", "87-1.json", "102-4.json"]

func sortWithCustomFormat(first: String, second: String) -> Bool{
    func extract(value: String) -> (Int, Int){
        return (Int(value.componentsSeparatedByString("-").first!)!, Int(value.componentsSeparatedByString("-").last!.componentsSeparatedByString(".").first!)!)
    }
    let firstNumber = extract(first)
    let secondNumber = extract(second)
    if firstNumber.0 != secondNumber.0 { return firstNumber.0 < secondNumber.0 }
    return firstNumber.1 < secondNumber.1
}

fileNames.sort(sortWithCustomFormat)

The function sortWithCustomFormat has a function extract that takes the inputted string and extracts the first and second numbers from it. Then, you compare the first numbers. If they are equal, then you compare the second numbers.

Sign up to request clarification or add additional context in comments.

5 Comments

I think we all came up with simple variants of the same solution, but I'm not seeing yours as quite working on the second field in Playground...
@Grimxn Can you give a set of file names that doesn't work so I can see what is wrong?
fileNames = ["7-4.json", "87-1.json", "102-4.json", "102-1.json"] doesn't seem to sort the last two in my Playground...
@Grimxn The problem was that I accidentally compared firstNumber.0 != secondNumber.1. Thanks for pointing that out.
No problem - glad to help.
0
var fileNames = ["87-1.json", "7-4.json", "87-3.json", "102-4.json"]
fileNames = fileNames.sort({ (s1, s2) -> Bool in

    let f1 = s1.stringByReplacingOccurrencesOfString(".json", withString: "")
    let f2 = s2.stringByReplacingOccurrencesOfString(".json", withString: "")

    let arr1 = f1.componentsSeparatedByString("-")
    let arr2 = f2.componentsSeparatedByString("-")


    var int1 = Int(arr1[0])
    var int2 = Int(arr2[0])

    if int1 < int2 {
        return true
    }
    else if int1 > int2 {
        return false
    }
    else {
        int1 = Int(arr1[1])
        int2 = Int(arr2[1])
        if int1 < int2 {
            return true
        }
        else if int1 > int2 {
            return false
        }
        else {
            return true
        }
    }
});
print(fileNames)

Comments

0

Try this...

var fileNames = ["87-1.json", "7-4.json", "102-4.json"] 
// Modded OP's order to actually test sort
var sorted = fileNames.sort{ $0 < $1 }
print(sorted) // ["102-4.json", "7-4.json", "87-1.json"]
// Not sorted as OP "required", as they are string sorted, not number sorted

// Very simplistic solution
sorted = fileNames.sort { ($0 as NSString).integerValue < ($1 as NSString).integerValue}
print(sorted) // As OP requires, but...

// It won't sort on his count field - add a failing case...
fileNames = ["7-4.json", "87-1.json", "102-4.json", "102-1.json"]
sorted = fileNames.sort { ($0 as NSString).integerValue < ($1 as NSString).integerValue}
print(sorted) // ["7-4.json", "87-1.json", "102-4.json", "102-1.son"]
// WRONG!

// Define a simple function that parses his strings into tuples.
// This assumes that the Strings are valid, and fails safe if not.
// If you want more validation, add it yourself!
func myParse(s: String) -> (Int, Int) {
    let c = s.componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: "-."))
    switch c.count {
    case 0:
        print("Careful Will Robinson!")
        return (0, 0)
    case 1:
        print("Careful Will Robinson!")
        return ((c[0] as NSString).integerValue, 0)
    default:
        return ((c[0] as NSString).integerValue, (c[1] as NSString).integerValue)
    }
}

let test = fileNames.map { myParse($0) }
print("\(test)") // Test execution of function

sorted = fileNames.sort { (s1: String, s2: String) -> Bool in
    let t1 = myParse(s1)
    let t2 = myParse(s2)
    if t1.0 == t2.0 {
        return t1.1 < t2.1
    } else {
        return t1.0 < t2.0
    }
}
print(sorted) // As required ["7-4.json", "87-1.json", "102-1.json", "102-4.json"]

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.