Skip to content

Instantly share code, notes, and snippets.

@brianmcallister
Last active August 29, 2015 14:20
Show Gist options
  • Save brianmcallister/f0e77c185f4a0d6f7172 to your computer and use it in GitHub Desktop.
Save brianmcallister/f0e77c185f4a0d6f7172 to your computer and use it in GitHub Desktop.
CoffeeScript natural sort. Ported from Dave Koelle's Alphanum Algorithm.
# 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