Skip to content

Instantly share code, notes, and snippets.

@robertmryan
Last active March 13, 2016 20:34
Show Gist options
  • Save robertmryan/ab76052ff4b7dd3eb4a1 to your computer and use it in GitHub Desktop.
Save robertmryan/ab76052ff4b7dd3eb4a1 to your computer and use it in GitHub Desktop.
//: **Sort strings by numeric values only; ignoring non-numeric portions of strings**
import Cocoa
//: Persuant to [http://stackoverflow.com/a/35962434/1271826](http://stackoverflow.com/a/35962434/1271826), this illustrates a more concise way to accomplish what Mountain Man posted. This suffers from the same limitations as his code, though:
//:
//: - non-continguous numbers will be treated as single number (e.g. "He is 5 feet 10 inches tall" will be `510`);
//: - does not handle negative numbers; and
//: - does not handle floating point numbers
var unsortedStrings = ["Dave7", "Bob8", "Cathy9", "Henry10", "Susan10", "Pat11", "Steve12", "Dan12", "Ken1", "Sean2", "Howard3", "Dixie3", "Newman5", "Billy6"]
let namesSortedByNumber = unsortedStrings
.map { string in (string, String(string.characters.filter { $0 >= Character("0") && $0 <= Character("9") })) }
.sort {
switch $0.1.compare($1.1, options: .NumericSearch) {
case .OrderedAscending:
return true
case .OrderedDescending:
return false
default:
return $0.0.compare($1.0) == .OrderedAscending
}
}.map { $0.0 }
//: This rendition sorts by the first floating point number (including negative numbers) encountered in the strings. This only considers the first number encountered, though.
unsortedStrings = ["129 celcius", "110.4 celcius", "-200 celcius"]
let regex = try! NSRegularExpression(pattern: "[+-]?\\d+(\\.\\d*)?", options: [])
let namesSortedByDecimalNumber = unsortedStrings
.map { string -> (String, Double?) in
if let match = regex.firstMatchInString(string, options: [], range: NSMakeRange(0, string.characters.count)) {
return (string, Double((string as NSString).substringWithRange(match.range)))
} else {
return (string, nil)
}
}.sort {
if $0.1 == $1.1 {
return $0.0 < $1.0
}
if $0.1 == nil {
return false
} else if $1.1 == nil {
return true
}
return $0.1! < $1.1!
}.map { $0.0 }
//: This rendition sorts by multiple floating point numbers encountered in the strings.
unsortedStrings = ["6 feet 1 inch", "5 feet 10 inches", "5 feet 2.5 inches", "5 feet 2 inches", "5 feet 1.5 inches"]
let namesSortedByDecimalNumbers = unsortedStrings
.map { string -> (String, [Double]) in
(string, regex.matchesInString(string, options: [], range: NSMakeRange(0, string.characters.count))
.map { match in Double((string as NSString).substringWithRange(match.range))! })
}.sort { (object0, object1) in
for index in (0 ..< (object0.1).count) {
if object1.1.count < index {
return false
}
let value0 = object0.1[index]
let value1 = object1.1[index]
if value0 < value1 {
return true
} else if value0 > value1 {
return false
}
}
if object1.1.count > object0.1.count {
return true
}
return object0.0 < object1.0
}.map { $0.0 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment