First a debugging tip with eval and dynamically created code. It is really helpful if you have the generated code displayed in error messages. Otherwise bad input can crash your code, but it can be hard to figure out why. Similarly I like using line directives as described at the bottom of perlsyn so that warnings come with nice descriptive messages about where the eval is in my code, rather than knowing that the error was at line 2 of eval 14. (merlyn showed me this trick.)

Also I don't like using autodetection of datatypes like you have above. My experience is that real-world data often throws you surprises like a field with mixed numbers and strings in it. I've run int that too often to trust code which will break on that case. (Although tye has a cute sprintf trick at Re: Sorting on Section Numbers which is acceptable with many datasets.)

That said, I have tackled this exact problem with closures. With something like this (untested):

# Take a list of sort functions, return a sort function # that tests them in order, with short circuit logic. sub ret_combined_sort_func { if (1 == @_) { return shift; } else { my @subs = @_; return sub { my $ret = 0; foreach (@subs) { $ret = $_->(); return $ret if $ret; } # I guess we're "out of sorts" :-) return 0; } } }
And now you can process the conditions, for each condition that you see, adding another subroutine to a list of known sort conditions. And then combine them as above to get a single sort function suitable for sticking in a sort. This part is straightforward if a bit tedious to write. (The main problem is settling on the format of the data structure that says which fields to sort in which directions.)

A note to people who like to generalize. I implicitly assume above that the sort functions are defined in the same package that sort will be called in. Or at least know the package. That is because the $a and $b that is set depends where sort is called, so the sort function had better look there. If you don't want to avoid that then you need to modify the closures to all use a ($$) prototype. sort will in recent (5.6 on up) versions of Perl then pass in the two scalars to compare rather than alias them in $a and $b. Now your sort functions can be defined in a different package than sort is eventually called in. (I thought that this was pointed out to me by dws. He doesn't remember that, and I can't find where it was pointed out. I've had several occasions to use it since though.)

Update: dws pointed out a piece of mangled grammar, and told me that he didn't remember telling me about using prototypes in a sort.

Update 2: "lease" should have been "least". Fixed.


In reply to Re: Fun with complex sorting on arbitrary criteria list. by tilly
in thread Fun with complex sorting on arbitrary criteria list. by davido

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.