Alphanumeric Sort

I need to sort a collection of book models by their title. These are technical books with long names including stuff like “Title 49, Parts 100-185”. My problem is that “Title 10” comes before “Title 2” because strings are sorted left-to-right by character.

My fix is to define an instance method:

def alpha_name
name.split(/\W+/).collect{|p| p.match(/^\d+$/) ? p.to_i : p}.to_s
end

And in my controller:

@products.sort! { |a,b| a.alpha_name <=> b.alpha_name }

Is there a better (more optimized or more elegant) way to do this? Would this sort of thing be useful in core?

Is there a better (more optimized or more elegant) way to do this? Would
this sort of thing be useful in core?

I'd say no, this sort of thing would not be useful (recommended) in
core. String based sorting is what it is (and is also affected by
language and locale). What you are doing is very specialized to your
application.

What I would do if it were my application is group the books into
volumes and chapters/parts. Then use these numeric attributes to
organize the book collections. Then you could have your database
perform your sorting, which would be much more efficient than do it
with array sorting.

I imagine for your specific case there would be three additional
attributes on your model [volume, begin_part, end_part]. Then :order
=> [ volume, begin_part ]. Then maybe use
"before_validation_on_create" to parse the book title and store the
three integer values in the database.

I’d say no, this sort of thing would not be useful (recommended) in core. String based sorting is what it is (and is also affected by language and locale).

Don’t numerals come before letters in all languages and locales?

What you are doing is very specialized to your application.

I think it has usefulness in a number of situations. Has anyone else had to do something like this?

What I would do if it were my application is group the books into

volumes and chapters/parts. Then use these numeric attributes to

organize the book collections. Then you could have your database

perform your sorting, which would be much more efficient than do it

with array sorting.

I imagine for your specific case there would be three additional

attributes on your model [volume, begin_part, end_part]. Then :order

=> [ volume, begin_part ]. Then maybe use

“before_validation_on_create” to parse the book title and store the

three integer values in the database.

That would work if all of the books in the database fit that model (title number and parts range). Most don’t, but a decent portion do. Others use volume numbers (“Vol. 1”, “Vol. 2”) or edition dates (“2008 Edition”).

The question was if there’s a more efficient way to perform the sort. Being able to have the database do the sort would be great, but the database (MySQL 5.1) can’t split a string and sort the resulting array.

Thanks,