Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Sorting issues

by hokie (Monk)
on Jan 09, 2004 at 14:15 UTC ( #320118=perlquestion: print w/replies, xml ) Need Help??

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

Monks,

I have 3 arrays of spatial data, @x @y @z. I want to sort them so that they are sorted first by @z in ascending order and then by @x in ascending order. So if I have:

@x = (0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36);
@y = (0, 0, 0, 18, 18, 18, 36, 36, 36, 0, 0, 0, 18, 18, 18, 36, 36, 36);
@z = (25, 25, 25, 25, 25, 25, 25, 25, 25, 20, 20, 20, 20, 20, 20, 20, 20, 20);

Then after sorting I am looking for:

@x = (0, 0, 0, 18, 18, 18, 36, 36, 36, 0, 0, 0, 18, 18, 18, 36, 36, 36);
@y = (0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36);
@z = (20, 20, 20, 20, 20, 20, 20, 20, 20, 25, 25, 25, 25, 25, 25, 25, 25, 25);

sorry for the long arrays and the easy question.

Replies are listed 'Best First'.
Re: Sorting issues
by borisz (Canon) on Jan 09, 2004 at 14:48 UTC
    here is one idea.
    @t = sort { $z[$a] <=> $z[$b] || $y[$a] <=> $y[$b] || $x[$a] <=> $x[$b +] } (0..$#z); @z = @z[@t]; @y = @y[@t]; @x = @x[@t];
    Boris
Re: Sorting issues
by Abigail-II (Bishop) on Jan 09, 2004 at 14:34 UTC
    Here's one way of doing it:
    my $i = 0; map {($z [$i], $x [$i], $y [$i ++]) = map {$_ + 0} split /;/} sort map {sprintf "%010d;%010d;%010d" => $z [$_], $x [$_], $y [$_]} 0 .. (@ +x - 1);

    Abigail

Re: Sorting issues
by Roger (Parson) on Jan 09, 2004 at 14:34 UTC
    use strict; use warnings; use Data::Dumper; my @x = (0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, + 36); my @y = (0, 0, 0, 18, 18, 18, 36, 36, 36, 0, 0, 0, 18, 18, 18, 36, 36, + 36); my @z = (25, 25, 25, 25, 25, 25, 25, 25, 25, 20, 20, 20, 20, 20, 20, 2 +0, 20, 20); my @sorted = sort { $a->[2] <=> $b->[2] or $a->[1] <=> $b->[1] or $a->[0] <=> $b->[0] } map { [ $x[$_], $y[$_], $z[$_] ] } 0 .. $#x; @x = @y = @z = (); foreach (@sorted) { push @x, $_->[0]; push @y, $_->[1]; push @z, $_->[2]; } print "@x\n@y\n@z\n";

    And the output is -
    0 18 36 0 18 36 0 18 36 0 18 36 0 18 36 0 18 36 0 0 0 18 18 18 36 36 36 0 0 0 18 18 18 36 36 36 20 20 20 20 20 20 20 20 20 25 25 25 25 25 25 25 25 25
Re: Sorting issues
by ysth (Canon) on Jan 09, 2004 at 14:43 UTC
    @x = (0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36, 0, 18, 36 +); @y = (0, 0, 0, 18, 18, 18, 36, 36, 36, 0, 0, 0, 18, 18, 18, 36, 36, 36 +); @z = (25, 25, 25, 25, 25, 25, 25, 25, 25, 20, 20, 20, 20, 20, 20, 20, +20, 20); @reindex = sort { $z[$a] <=> $z[$b] || $x[$a] <=> $x[$b] } 0..$#x; @x=@x[@reindex]; @y=@y[@reindex]; @z=@z[@reindex]; use Data::Dumper; print Dumper \@x; print Dumper \@y; print Dumper \@z;
Re: Sorting issues
by Skylark (Beadle) on Jan 09, 2004 at 16:41 UTC
    Ok, they say "never assume", but I'm gonna suggest a different answer than the others given so far, based on the following assumption: Aren't your arrays actually triplets of coordinates, each triplet ($x[$i], $y[$i], $z[$i]) representing a point in 3D?

    If that is the case, might I suggest a change in data structures?
    my @points; # This will add one point (the first one in your arrays # above) to another type of data structure. my %this_point = {x => 0, y => 0, z => 25}; push @points, \%this_point; # Do this for as many points as you have. You can # adapt the method you use to fill your three arrays # to create this kind of data structure using the # example above.
    That would allow you to refer to the X component of a point $i as:
    $points[$i]->{x}

    Then, the sorting becomes a bit easier:
    # Sort by z first, then sort by x for each point @points = sort { $a->{x} <=> $b->{x} } sort { $a->{z} <=> $b->{z} } @points;
    (note: untested, but should give you the idea)

    I find this data structure more intuitive, since the triplets of coordinates, which are related (they form a point in 3D), are actually together in the data structure, whereas in the arrays in your original post they are separated.
      I find this data structure more intuitive

      Just be aware that you'll be using 3-4 times the memory for this data structure. For a relatively small number of points its fine, but you can squeeze more points into memory if you just use plain arrays like the OP has.

      BTW, your sort does not work. You can't do sequential sorts and expect it to still be sorted by the previous order (although it sometimes might appear to work, it doesn't always).

        > Just be aware that you'll be using 3-4 times the memory for this data structure.

        Thanks for pointing that out, I didn't know.
        update: Now that I think of it, I find it unfortunate that better design would carry such a high cost... But I know, that's Perl: equivalent speed at the cost of higher resource usage.

        > You can't do sequential sorts and expect it to still be sorted by the previous order

        Hmmm, didn't think about that. For my personal knowledge, then, how would you sort by one criteria and then by another? Something similar to the above?
        sort { $a->{z} <=> $b->{z} || $a->{x} <=> $b->{x} } @points;
        ???
      There's no promise that sort is stable there (and it wasn't, depending on the version of Perl that you are using). Other solutions in this thread do the trick with a single sort: please look at those.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        merlyn: Agreed, my "combination sort" isn't the greatest. But the OP can combine the sort from other posts with the idea about changing the way his data is structured from my post to solve his problem.

        My main point was about the data structure's design more closely modeling the data itself. But thanks for your comment anyways, it's very true.

        update: subject line
Re: Sorting issues
by Abigail-II (Bishop) on Jan 09, 2004 at 14:22 UTC
    What have you tried so far? Did you try any code at all? Did you try searching for an answer? You aren't the first person with this problem....

    Abigail

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://320118]
Approved by b10m
Front-paged by blue_cowdawg
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (3)
As of 2022-06-26 08:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My most frequent journeys are powered by:









    Results (84 votes). Check out past polls.

    Notices?