in reply to Twisted sort requirements
You can get most of what you need with a Schwartzian Transform, but there's one little wrinkle that complicates things: during the first map, when you run across an arbitrary title (say, 'postmodernism' by 'lisa'), you don't yet know whether the same author also has a 'THIS BOOK FIRST' title. So you need an extra pass, and an orcish manoeuver, to tell you that.
(If terms like 'Schwartzian Transform' and 'orcish manoeuver' are new for you, you should first look those up (Google is good here) and try to understand them before trying to use the code below.)
my %orcish; my @sorted = map { # Final pass: restore the original datum, dropping # the extra stuff we added in the second pass: $$_[4] } sort { # Books whose author has a 'THIS BOOK FIRST' title are first: $$a[0] <=> $$b[0] # Within that, sort by author: or $$a[1] <=> $$b[1] # Within that, sort by whether it's THIS BOOK FIRST or not: or $$a[2] <=> $$b[2] # Within that, sort by the title, alphabetically: or $$a[3] <=> $$b[3] } map { # Second pass: gather enough info that sort can sort like we want: [$orcish{$$_{author}}, $$_{author}, ($$_{title} eq 'THIS BOOK FIRST'), $$_{title}, $_] } map { # First pass: take note of which authors have 'THIS BOOK FIRST': $orcish{$$_{author}}++ if $$_{title} eq 'THIS BOOK FIRST'; # But just pass through the data unmodified for now: $_ } @things_to_sort;
Note that the way I've written this, if an author has _two_ books with the magic title, that author's works will be listed before the ones who only have _one_ such title. If this is undesireable, change the ++ to =1 in the first pass.
Also note that with this structure in place it's easy to now make further refinements to the sort order, by making slight modifications to the second pass and/or the sort. For instance, if I wanted the words "A", "An", and "The" on the beginnings of titles to be ignored for sorting purposes, then in the second pass, instead of using $$_{title} directly, I would use title_for_sort_purposes($$_{title}) and then write that subroutine to strip initial articles from its input and return what is left. Case unification could also be performed, whitespace consolidation, and whatever other forms of normalization you desire. The author's name, too, can be handled in this way, and in fact could be parsed and the last name split out (if your author names aren't already in "last, first" form), and so forth. The original data are retained as the last element in each anonymous array, so you can go nuts making adjustments to the other elements to tweak how they sort, without changing how they appear once sorted.
|
|---|