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,