Sorting interview question

I have been busy with my new position, so I haven't been able to put as much time and thought into my blog posts.

I have question that was asked of me on my job interview:

You have an array of items, each element matches the following pattern:
You want to sort the array both alphabetically and numerically:

ie 'abc123' comes after 'abc2' because 2<123 when compared numerically.

How would you do this?

Can you do it in one line code? Mine wasn't but I still got the job, However I have seen it in one line of code.


my @sorted = map  { $_->[0] }
             sort { $a->[2] cmp $b->[2] } 
             sort { $a->[3]  $b->[3] } 
             map  {[$_, split(/^([a-zA-Z]+)([0-9]+)/) ] } @list;

Just a stab at it. My limited test seemed to work.

Brain's tired so I haven't thought about why the second index is empty...maybe I'll think about it tomorrow...or not.

I suspect someone could golf this, but:

my @sorted = sort { ( ($a, $b) =~ s/\d*// && $a cmp $b ) || ( ($a, $b) =~ s/[^\d]*// && $a <=> $b) } @unsorted;

I tested this with the following one-liner:

$perl -E'say for sort { ( ($a, $b) =~ s/\d*// && $a cmp $b ) || ( ($a, $b) =~ s/[^\d]*// && $a <=> $b) } @ARGV' -- abc123 abc2 aa1 az0 aa2

my oneliner:

sort { sub { $_[0] cmp $_[2] or $_[1] <=> $_[3] }->( map /^([a-zA-Z]+)([0-9]+)$/,($a,$b) ) } @arr;

Chris Prather, your example in not so right

($a,$b) =~ s/// works like $b =~ s///

and i found THE BEST SOLUTION for this question:

sort { $a cmp $b or $a <=> $b } @unsorted

TA DA!!!!

use Sort::Naturally qw(nsort);
nsort @list;

You can join that to a single line if you feel like...

> and i found THE BEST SOLUTION for this question:
> sort { $a cmp $b or $a $b } @unsorted
> TA DA!!!!

I was wrong, $a $b never happens.

Right values to test is 'a1' and 'a02'

I think this just is all sorts of win (no pun intended).

Okay so lemme update a bit, this combines basically everything people have had. It's longer than the sort { sub {...}->(map // $a,$b) } but I think a bit clearer.

@sorted =
map { local $"; "@$_" }
sort { $$a[0] cmp $$b[0] or $$a[1] <=> $b[1] }
map { [/(\w+)(\d+)/] }

Or in one-liner for the command line

$perl -E'say for map { local $"; "@$_" } sort { $$a[0] cmp $$b[0] or $$a[1] <=> $$b[1] } map { [/(\w+)(\d+)/] } @ARGV' -- a13 aa03 a1 aa2 a02

I like the Sort::Natural solution best though :)

About this Entry

This page contains a single entry by leonard published on April 10, 2010 5:32 PM.

Rule of threes was the previous entry in this blog.

Perls of wisdom is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.