• compare two sorted array, item by item, which one is bigger

    From hymie!@hymie@nasalinux.net to comp.lang.perl.misc on Sat Feb 24 19:14:49 2024
    From Newsgroup: comp.lang.perl.misc

    I'm sure this is an FAQ if I can just find the correct words to ask my question.

    I have two people, 0 and 1, which are denoted by the $player variable.

    I have a hash of sorted arrays

    @{$scores{$player}}
    104 92 92 90 87
    104 92 92 89 88

    And I have a %percent hash that holds the sum of those elements.
    In this case, $percent{$player} is 465 for both.

    (I can safely assume that all numbers are non-negative, so I'm fine with
    an empty value being treated as zero)

    (I also have a bunch of lousy code that I'm not proud of)

    So I have this construct

    foreach $player (sort {$percent{$b} <=> $percent{$a}} keys %percent)

    that will sort the %percent hash by value ... but since the two are
    equal, I think I'm getting a random choice.

    So then I wrote this construct

    foreach $player (sort
    {$percent{$b} <=> $percent{$a} || ${$scores{$b}}[0] <=> ${$scores{$a}}[0] } keys %percent)

    which will check the first element in each array from the %scores hash
    to see which value is larger.

    The question is -- how can I (or can I) programatically keep checking
    entries in the arrays of the %scores hash until I find a pair of
    entries that are not equal? I'd rather not have (in my case) 9
    individual tests of the items. Is there a simple subroutine I can
    use?

    My first thought is to compare $a[0] and $b[0] ... and then if they're
    the same, shift them both and try again. But I'm a little nervous that shifting the arrays will lose the values, and I don't want to do that.
    My second thought is use an array slice -- if $a[0] == $b[0] then
    recursively check $a[1-x] against $b[1-x] ...

    I'm hoping somebody knows something simpler.

    Thanks.

    --hymie! https://nasalinux.net/~hymie hymie@nasalinux.net --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Rainer Weikusat@rweikusat@talktalk.net to comp.lang.perl.misc on Mon Feb 26 16:20:55 2024
    From Newsgroup: comp.lang.perl.misc

    hymie! <hymie@nasalinux.net> writes:
    I have two people, 0 and 1, which are denoted by the $player variable.

    I have a hash of sorted arrays

    @{$scores{$player}}
    104 92 92 90 87
    104 92 92 89 88

    And I have a %percent hash that holds the sum of those elements.
    In this case, $percent{$player} is 465 for both.

    [...]

    So I have this construct

    foreach $player (sort {$percent{$b} <=> $percent{$a}} keys %percent)

    that will sort the %percent hash by value ... but since the two are
    equal, I think I'm getting a random choice.

    So then I wrote this construct

    foreach $player (sort
    {$percent{$b} <=> $percent{$a} || ${$scores{$b}}[0] <=> ${$scores{$a}}[0] } keys %percent)

    which will check the first element in each array from the %scores hash
    to see which value is larger.

    The question is -- how can I (or can I) programatically keep checking
    entries in the arrays of the %scores hash until I find a pair of
    entries that are not equal?

    If you're arrays are always of equal length, you could use

    sub ary_cmp
    {
    my ($a0, $a1) = @_;
    my $rc;

    for (0 .. $#$a0) {
    $rc = $$a0[$_] - $$a1[$_];
    return $rc < 0 ? -1 : 1 if $rc;
    }

    return 0;
    }

    otherwise, it's a bit more difficult.

    sub ary_cmp
    {
    my ($a0, $a1) = @_;
    my ($last, $rc);

    $last = $#$a0;
    $_ < $last and $last = $_ for $#$a1;

    for (0 .. $last) {
    $rc = $$a0[$_] - $$a1[$_];
    return $rc < 0 ? -1 : 1 if $rc;
    }

    return @$a0 <=> @$a1;
    }

    could do.
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Rainer Weikusat@rweikusat@talktalk.net to comp.lang.perl.misc on Tue Feb 27 15:37:33 2024
    From Newsgroup: comp.lang.perl.misc

    Rainer Weikusat <rweikusat@talktalk.net> writes:
    hymie! <hymie@nasalinux.net> writes:

    [...]

    foreach $player (sort
    {$percent{$b} <=> $percent{$a} || ${$scores{$b}}[0] <=> ${$scores{$a}}[0] } >> keys %percent)

    which will check the first element in each array from the %scores hash
    to see which value is larger.

    The question is -- how can I (or can I) programatically keep checking
    entries in the arrays of the %scores hash until I find a pair of
    entries that are not equal?

    If you're arrays are always of equal length, you could use

    sub ary_cmp
    {
    my ($a0, $a1) = @_;
    my $rc;

    for (0 .. $#$a0) {
    $rc = $$a0[$_] - $$a1[$_];
    return $rc < 0 ? -1 : 1 if $rc;
    }

    return 0;
    }

    This can be simplified somewhat by using the <=> operator for the check
    inside the loop as that already produces the desired result of either
    -1, 0 or 1.

    sub ary_cmp
    {
    my ($a0, $a1) = @_;

    for (0 .. $#$a0) {
    $_ and return $_ for $$a0[$_] <=> $$a1[$_];
    }

    return 0;
    }
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From hymie!@hymie@nasalinux.net to comp.lang.perl.misc on Wed Feb 28 15:35:22 2024
    From Newsgroup: comp.lang.perl.misc

    In our last episode, the evil Dr. Lacto had captured our hero,
    Rainer Weikusat <rweikusat@talktalk.net>, who said:
    hymie! <hymie@nasalinux.net> writes:
    The question is -- how can I (or can I) programatically keep checking
    entries in the arrays of the %scores hash until I find a pair of
    entries that are not equal?

    If your arrays are always of equal length, you could use

    I don't think I can depend on that :(

    otherwise, it's a bit more difficult.

    sub ary_cmp
    {
    my ($a0, $a1) = @_;
    my ($last, $rc);

    # we need the length of the shorter array
    # start with the length of array a0
    # and see if the length of array a1 is less
    $last = $#$a0;
    $_ < $last and $last = $_ for $#$a1;

    # for each entry in the shorter array
    # compare that numbered entry in the two arrays
    # return <=> if the result is not 0
    for (0 .. $last) {
    $_ and return $_ for $$a0[$_] <=> $$a1[$_];
    }

    # all of the elements are equal, so return the longer array
    return @$a0 <=> @$a1;
    }

    I took the liberty of adding your improvement to this function.

    I'll definitely try this out and see how well it work.

    I have a few followup questions...

    (*) I added some comments. Can you tell me if I'm correct?

    (*) Could I have set $last this way?

    $last = $#$a0 < $#$a1 ? $#$a0 : $#$a1 ;

    or

    $last = @$a0 < @$a1 ? @$a0 : @$a1 ;

    ?

    (*) In this construct

    for (0 .. $last) {
    $_ and return $_ for $$a0[$_] <=> $$a1[$_];

    is it safe to reuse $_ like that? The scoping will work itself out,
    even without a bracket set?

    Thank you very much.

    --hymie!
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Rainer Weikusat@rweikusat@talktalk.net to comp.lang.perl.misc on Wed Feb 28 16:34:35 2024
    From Newsgroup: comp.lang.perl.misc

    hymie! <hymie@nasalinux.net> writes:
    In our last episode, the evil Dr. Lacto had captured our hero,
    Rainer Weikusat <rweikusat@talktalk.net>, who said:
    hymie! <hymie@nasalinux.net> writes:
    The question is -- how can I (or can I) programatically keep checking
    entries in the arrays of the %scores hash until I find a pair of
    entries that are not equal?

    If your arrays are always of equal length, you could use

    I don't think I can depend on that :(

    otherwise, it's a bit more difficult.

    sub ary_cmp
    {
    my ($a0, $a1) = @_;
    my ($last, $rc);

    # we need the length of the shorter array
    # start with the length of array a0
    # and see if the length of array a1 is less
    $last = $#$a0;
    $_ < $last and $last = $_ for $#$a1;

    # for each entry in the shorter array
    # compare that numbered entry in the two arrays
    # return <=> if the result is not 0
    for (0 .. $last) {
    $_ and return $_ for $$a0[$_] <=> $$a1[$_];
    }

    # all of the elements are equal, so return the longer array
    return @$a0 <=> @$a1;
    }

    I took the liberty of adding your improvement to this function.

    I'll definitely try this out and see how well it work.

    I have a few followup questions...

    (*) I added some comments. Can you tell me if I'm correct?

    Yes.


    (*) Could I have set $last this way?

    $last = $#$a0 < $#$a1 ? $#$a0 : $#$a1 ;

    or

    $last = @$a0 < @$a1 ? @$a0 : @$a1 ;

    The first yes, second no as $#$a0 == @$a0 - 1. It's just syntactically a
    bit more repetitive.


    ?

    (*) In this construct

    for (0 .. $last) {
    $_ and return $_ for $$a0[$_] <=> $$a1[$_];

    is it safe to reuse $_ like that?

    Yes. The foreach-for aliases a localized $_ to the first element and
    then executes the loop body, ie, either the block in case of for (...) {
    } or the statement for the statement modifier. Then, it does the same
    with the second element and so forth, until the body has been run for
    all list elements. This means $_ reverts back to the current index after
    the

    $_ and return $_

    has been executed.
    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From Bouras George@g-bouras@otenet.gr to comp.lang.perl.misc on Mon May 20 13:09:28 2024
    From Newsgroup: comp.lang.perl.misc

    On 24/2/2024 9:14 μ.μ., hymie! wrote:
    I'm sure this is an FAQ if I can just find the correct words to ask my question.

    I hope it is not too late for this, or whatever.
    My usenet account was deleted , just create a new one , and have a look
    at my favorite group.

    About the request now.
    We must stop writing code no matter the language , everything is about
    the right data structures for every specific problem.
    So here it is. Thanks, George Bouras

    ---------------------------


    #!/usr/bin/perl
    use strict; use warnings; use feature qw/say/;
    use Data::Dumper; $Data::Dumper::Purity=1; $Data::Dumper::Terse=1; $Data::Dumper::Indent=1;
    my ($i, %scores, %percent)=(0,,);

    $scores{0} = [
    [ qw(104 92 92 90 87) ],
    [ qw(104 92 92 89 88) ],
    [ qw(1 1 1 1 1 ) ],
    [ qw(2 2 2 2 2 ) ]
    ];

    $scores{1} = [
    [ qw(1 2 3 4 5) ],
    [ qw(5 1 2 3 4) ],
    [ qw(3 3 3 3 3) ],
    [ qw(4 4 4 4 4) ]
    ];


    # Fill the %percent with sums per user for every list
    $,=',';
    foreach my $player (keys %scores) {
    $i=0;
    foreach my $list ( @{ $scores{$player} } ) {
    push @{$percent{$player}->{ sub {my $s=0; map { $s += $_ } @{$_[0]}; $s}->($list)} } , $i++
    }
    }

    #print Dumper $scores{0};
    #print Dumper $scores{1};
    #print Dumper \%percent;

    # Just print two different list sums of %percent of the person 0
    #$"=',';
    $i=-1;
    foreach (keys %{$percent{0}}) {
    last if 2 == ++$i;
    say "person:0 , sum:$_, scores_list_offset=@{$percent{0}->{$_}}"
    }


    --- Synchronet 3.20a-Linux NewsLink 1.114
  • From ram@ram@zedat.fu-berlin.de (Stefan Ram) to comp.lang.perl.misc on Tue May 21 08:48:11 2024
    From Newsgroup: comp.lang.perl.misc

    Bouras George <g-bouras@otenet.gr> wrote or quoted:
    We must stop writing code no matter the language , everything is about
    the right data structures for every specific problem.

    Rob Pike's "Rule 5" Data dominates:

    |If you've chosen the right data structures and organized things
    |well, the algorithms will almost always be self-evident.
    |Data structures, not algorithms, are central to programming.

    .
    --- Synchronet 3.20a-Linux NewsLink 1.114