ww has asked for the wisdom of the Perl Monks concerning the following question:

Shortform: I need to take submitted data (consisting of multiple cases of { In=n Pn=decimalprice Qn=quantity ITn=price*quant } , perhaps discounted by js in the original page; validate it, and spit it back out to a new page in the original order, omitting the rows where Qn=(0 || undef).

At your own risk (or kindness), please read on...

Given:
  1. <apologetically> an ignorance, on my part, of db approaches... <apologetically>
  2. an ecommerce webpage where a typical row looks like this:
    <td scope="row">A. millefolium 'Summer Wine'<input type="hidden" name= +"I1" value="A. millefolium 'Summer Wine'"></td> <td><label for="Q1"><input type="text" id="Q1" name="Q1" size="3" onch +ange="calc_item(order,6);"></label></td> <td><label for="P1">1 gal <input type="text" id="P1" name="P1" value=" +3.95" onfocus="this.blur();" size="4"></label></td> <td><label for="IT1"><input type="text" id="IT1" name="IT1" value="0" +size="6" onfocus="this.blur();"></label></td>
  3. a hash, created (using a homebrew script which uses cgi.pm) by posting from a webpage orderform.
    The hash looks like this:
    %form = ( 'IT3' => '6.99', 'I0' => '0', 'I3' => '3', 'Q3' => '1', 'P0' => '3.95', 'IT0' => '129.05', 'P3' => '6.99', 'Q0' => '40', 'IT10' => '36.50', 'P10' => '3.65', 'I10' => '10', 'Q10' => '10' <... snip> );

While it's trivial to sort that alphabetically by

foreach(sort keys %form) { print "$_ $form{$_} \n"; }
which gives me
I0 0 I10 10 I3 3 IT0 129.05 IT10 36.50 IT3 6.99 P0 3.95 P10 3.65 ...

But what I really seek is a way to get ALL the elements of the hash back into the same order in which they were submitted (ie, same order as in the intial webpage) -- because after unTainting, valdiating, removing items for which Qn and/or ITn are 0 and so on, the script uses them to populate a confirmation page ("Here's what I think you ordered; OK?)

One (perhaps "half-baked") notion is to extract the keys, split each between the alpha(s) and the digit(s)like:
\t "I[" . 0 . "]" .... "I[" . 570 ."]"
and <begin bewilderment> then get the whole mish-mash to look like:
%form = ( 'I0' => '0', 'Q0' => '40', 'P0' => '3.95', 'IT0' => '129.05', 'I3' => '3', 'Q3' => '1', 'P3' => '6.99', 'IT3' => '6.99', 'I10' => '10', 'Q10' => '10' 'P10' => '3.65', 'IT10' => '36.50', ... 'IT647' => 741.34 );

...because I don't really have any idea how to create the confirmation page's (600+ products omitting the quant=0 items) otherwise.
 
<++bewilderment> Truth be told, I'm not even sure whether this is a design question, an algorithm question or a reasonable question for the Monestary.
</bewilderment> Nonetheless, I'm seeking pointers and advice. Thanks for reading!

Replies are listed 'Best First'.
Re: sorting mixed alpha_digit keys of a hash?
by jdporter (Paladin) on Mar 22, 2006 at 19:04 UTC

    Perhaps it would help to have a hash which remembers the order in which items were added. If so, see Tie::IxHash. Then, you'd get the keys in the order the hash wants to give them to you, i.e. don't sort keys, just keys.

    We're building the house of the future together.
Re: sorting mixed alpha_digit keys of a hash?
by japhy (Canon) on Mar 22, 2006 at 19:33 UTC
    What you want to do is take each key name and split it into the letter half and the digit half, and use these as keys in a multi-dimensional hash:
    my %data; for my $k (keys %form) { # assumes all the keys are non-numbers followed by numbers my ($letters, $numbers) = $k =~ /(\D+)(\d+)/; $data{$numbers}{$letter} = $form{$k}; }
    Now your %data hash has the I, Q, P, and IT fields grouped by the number following them.

    If you'd rather just sort the keys in this manner and not produce a whole new data structure, I suggest:

    # UPDATE (fixed indices!) my @sorted_keys = map { $_->[0] } sort { $a->[2] <=> $b->[2] or $a->[1] cmp $b->[1] } map { [$_, /(\D+)(\d+)/] } keys %form;
    This is a standard Schwartzian Transform.

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: sorting mixed alpha_digit keys of a hash?
by zer (Deacon) on Mar 22, 2006 at 19:09 UTC
    how are you saving these values? is it a CGI form?
    @ARGV should hold the values that you need in the order it was sent. Copy it before modules get called and you should be on the right track... show us some code of this
      zer I stumbitted the question, inadvertently, before finishing, so some of the info you ask may have been missing when you replied. In any case, thank you!

      As I will with the suggestion from jdporter (above), I'll explore yours, as my quick test seems to suggest a way to simplify my code, greatly (the size, length of what exists is why the OP does not have a great deal of code since it's merely routine cgi- and hash-handling techniques which are well known).

      in the html form, action invokes confirm.pl, and submit POSTs the sample row and 600+ others, plus some other stuff. confirm.pl undertakes to delete the items for which there is no quantity (ie, not ordered today) and the other processing I mentioned, and then creates -- dynamically, I suppose one could say -- a new (shorter!) page which the customer can review and approve (in which case, another script ships off the order, a confirmation email, etc) or revise (eg, if ordered 100 but intended to order 500 of item In.}

      Hope to build a decent way to add items, too, but that's a mere glimmering. For now, the vendor will be happy with a site that says (implicitly), "If you missed an item, send the rest and then go back to go to send another order."