Discussion:
compare two sorted array, item by item, which one is bigger
(too old to reply)
hymie!
2024-02-24 19:14:49 UTC
Permalink
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 ***@nasalinux.net
Rainer Weikusat
2024-02-26 16:20:55 UTC
Permalink
Post by hymie!
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.
[...]
Post by hymie!
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.
Rainer Weikusat
2024-02-27 15:37:33 UTC
Permalink
[...]
Post by Rainer Weikusat
Post by hymie!
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 $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;
}
hymie!
2024-02-28 15:35:22 UTC
Permalink
In our last episode, the evil Dr. Lacto had captured our hero,
Post by hymie!
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 ($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
}
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!
Rainer Weikusat
2024-02-28 16:34:35 UTC
Permalink
Post by hymie!
In our last episode, the evil Dr. Lacto had captured our hero,
Post by hymie!
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 ($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
}
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.
Post by hymie!
(*) Could I have set $last this way?
$last = $#$a0 < $#$a1 ? $#$a0 : $#$a1 ;
or
The first yes, second no as $#$a0 == @$a0 - 1. It's just syntactically a
bit more repetitive.
Post by hymie!
?
(*) 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.
Bouras George
2024-05-20 10:09:28 UTC
Permalink
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}->{$_}}"
}
Stefan Ram
2024-05-21 08:48:11 UTC
Permalink
Post by Bouras George
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.

.

Loading...