Last active
August 29, 2015 14:20
-
-
Save brianmcallister/f0e77c185f4a0d6f7172 to your computer and use it in GitHub Desktop.
CoffeeScript natural sort. Ported from Dave Koelle's Alphanum Algorithm.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Public: Natural sort an array. | |
# https://gist.github.com/brianmcallister/f0e77c185f4a0d6f7172 | |
# Ported to CoffeeScript from: http://www.davekoelle.com/files/alphanum.js | |
# See: http://www.davekoelle.com/alphanum.html | |
# | |
# This function has been modified to support passing in an array as an | |
# argument, as opposed to attaching this function to the Array prototype. | |
# | |
# array - Array to natural sort. | |
# | |
# Returns the sorted array. | |
naturalSort: (array) -> | |
# First, chunk each index in the `array` into separate number and letter | |
# parts. If an index in the array looks like 'hello 1234', we're going to | |
# split it up into the following: | |
# | |
# ['hello ', '1234'] | |
# | |
# So, if the index looks like 'abc 123 def', the array will look like: | |
# | |
# ['abc ', '123', ' def'] | |
# | |
# This will allow us to compare each part of the array later, in our sort | |
# method. | |
for item, index in array | |
array[index] = new Array() | |
# As we iterate over each character in the the item, keep track if we're | |
# iterating over a group of letters or a group of numbers. | |
isNumberGroup = undefined | |
for letter in "#{item}" | |
code = letter.charCodeAt 0 | |
isNumber = 48 <= code <= 57 | |
# Create a new index in the array when the state of the group changes. | |
if isNumber isnt isNumberGroup | |
array[index].push '' | |
isNumberGroup = isNumber | |
array[index][array[index].length - 1] += letter | |
# Next, sort the array. | |
array.sort (a, b) -> | |
index = 0 | |
# Check each index in the two arrays. | |
while (aa = a[index]) and (bb = b[index]) | |
aa = aa.toLowerCase() | |
bb = bb.toLowerCase() | |
# If `aa` and `bb` are the same, continue until we find a difference. | |
if aa is bb | |
index = index + 1 | |
continue | |
# If both `aa` and `bb` are numbers, sort based on their value. | |
aaNumber = Number aa | |
bbNumber = Number bb | |
if aaNumber and typeof aaNumber is 'number' and | |
bbNumber and typeof bbNumber is 'number' | |
return aaNumber - bbNumber | |
# If `aa` and `bb` are strings, sort as normal. | |
return if aa > bb then 1 else -1 | |
# If everything is the same up until the lengths differ, sort the shorter | |
# string at a lower index. | |
return a.length - b.length | |
# Finally, rebuild each index in the now sorted array. | |
for item, index in array | |
array[index] = array[index].join '' | |
return array |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment