Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
I'm try to get the min value and position in array1. Then get the value in the same position from array 2.
#!usr/bin/perl
use Tkx;
use Tkx::Pane;
use Cwd;
use strict;
use warnings;
use List::Util 'max';
use List::Util 'min';
use Statistics::Descriptive 'mindex';
my @array1 = (1,2,3,4,5,6,7);
my @array2 = ("a","b","c","d","e","f","g");
my $min = min(@array1);
my $min_index = Statistics::Descriptive::Sparse->new();
$min_index -> mindex(@array1);
print "$min\n";
print "$min_index\n";
Re: min and mindex
by rjt (Curate) on Nov 06, 2012 at 17:28 UTC
|
#!/opt/local/bin/perl
use strict;
use warnings;
use List::MoreUtils qw(firstidx minmax);
my @array1 = qw(9 8 7 1 2 3 4 5 6 7);
my @array2 = qw(i h g a b c d e f g);
my $min = (minmax @array1)[0];
my $mindex = firstidx { $_ eq $min } @array1;
print "min = $min, mindex = $mindex, array2[$mindex] = $array2[$mindex
+]\n";
This does scan @array1 twice, but that will not be an issue for small arrays, and if you are using the XS version of List::MoreUtils, this implementation may still be faster than rolling your own min/mindex code. | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: min and mindex
by Khen1950fx (Canon) on Nov 06, 2012 at 19:13 UTC
|
Maybe this can be of some help:
#!usr/bin/perl -l
BEGIN {
$| = 1;
$^W = 1;
}
use strict;
use warnings;
use Statistics::Descriptive;
use List::Util qw(minstr maxstr);
my(@array1) = qw(1 2 3 4 5 6 7);
my $min_index = Statistics::Descriptive::Sparse->new();
$min_index->add_data(@array1);
my $min = $min_index->min;
my $max = $min_index->max;
my $mindex = $min_index->mindex;
print "Min: ", $min, minstr 'a'..'g';
print "Max: ", $max, maxstr 'a'..'g';
print "Mindex: ", $mindex;
print "Mindex: ", $min_index->mindex('a'..'g');
| [reply] [Watch: Dir/Any] [d/l] |
Re: min and mindex
by Kenosis (Priest) on Nov 06, 2012 at 17:37 UTC
|
Given your one-to-one mapping between the two arrays (i.e., the same number of elements) and the numbers in @array1 are not repeated, consider the following:
use strict;
use warnings;
use List::Util 'min';
my %hash;
my @array1 = ( 5, 2, 3, 4, 1, 6, 7 );
my @array2 = ( "a", "b", "c", "d", "e", "f", "g" );
my %array1Hash = map { $array1[$_] => $_ } 0 .. $#array1;
@hash{@array1} = @array2;
my $array1Min = min @array1;
print 'The minimum value in @array1 is ', $array1Min, ".\n";
print 'The position of ', $array1Min, ' in @array1 is ',
$array1Hash{$array1Min}, ".\n";
print 'The element in @array2 at position ', $array1Min, ' is ',
$hash{ min @array1 }, '.';
Output:
The minimum value in @array1 is 1.
The position of 1 in @array1 is 4.
The element in @array2 at position 1 is e.
Two hashes are created. The first (%array1Hash) pairs each element of @array1 with its position in the array. The second (%hash) pairs the elements of @array1 as the keys with the elements of @array2 as values. When you've found the minimum value in @array1, you can use it as the key to get the associated value from @array2.
Hope this helps!
Update: Added printing the min val of @array1 and that element's position in the array. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
I like this example. What would you do if the values in array1 were not unique?
| [reply] [Watch: Dir/Any] |
|
use strict;
use warnings;
use List::Util 'min';
my %array1Hash;
my @array1 = ( 5, 2, 1, 4, 1, 6, 7 );
my @array2 = ( "a", "b", "c", "d", "e", "f", "g" );
push @{ $array1Hash{ $array1[$_] } }, $_ for 0 .. $#array1;
my %array2Hash = map { $_ => $array2[$_] } 0 .. $#array2;
my $array1Min = min @array1;
my $positions = join ', ', @{ $array1Hash{$array1Min} };
my $elements = join ', ', map $array2Hash{$_}, @{ $array1Hash{$array1
+Min} };
print 'The minimum value in @array1 is ', "$array1Min.\n";
print 'The position(s) of ', $array1Min, ' in @array1: ', "$positions.
+\n";
print 'The element(s) in @array2 at position(s) ', "$positions: $eleme
+nts.";
Output:
The minimum value in @array1 is 1.
The position(s) of 1 in @array1: 2, 4.
The element(s) in @array2 at position(s) 2, 4: c, e.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: min and mindex
by kcott (Archbishop) on Nov 06, 2012 at 22:06 UTC
|
The first problem here is that you haven't asked a question! Perhaps ...
-
you don't understand why you're getting the output you see (which you don't show)
-
you want to know how to get the expected output (which you don't specify)
-
you don't understand some part of the documentation
-
you want a different way to do it
Please read the guidelines in: How do I post a question effectively?
The code you've provided outputs:
1
Statistics::Descriptive::Sparse=HASH(0x7fa3510457f0)
Presumably you want:
1
0
Checking the documentation for Statistics::Descriptive, you can achieve this by changing
my $min_index = Statistics::Descriptive::Sparse->new();
$min_index -> mindex(@array1);
to
my $stat = Statistics::Descriptive::Sparse->new();
$stat->add_data(@array1);
my $min_index = $stat->mindex();
See also ++Khen1950fx's response (above) which has similar code changes.
I see a number of alternative ways of doing this (without using Statistics::Descriptive) have already been provided. Here's another one that doesn't use any modules at all and handles non-unique values and arrays of uneven lengths.
#!/usr/bin/env perl
use strict;
use warnings;
my @data = (
[ [ 1 .. 7 ], [ qw{a b c d e f g} ] ],
[ [ 1 .. 7, 0 ], [ qw{a b c d e f g} ] ],
[ [ 1 .. 7, 0 ], [ qw{a b c d e f g h} ] ],
[ [ 1 .. 7, -1, 0 ], [ qw{a b c d e f g h} ] ],
[ [ 1 .. 7, 1 .. 7 ], [ qw{a b c d e f g} ] ],
);
for (@data) {
my @array1 = @{$_->[0]};
my @array2 = @{$_->[1]};
my $pos = -1;
my $min_pos = (
sort { $a->[0] <=> $b->[0] } map { [$_ => ++$pos] } @array1
)[0];
print "Array1: @array1\n";
print "Min value: $min_pos->[0]\n";
print "Min index: $min_pos->[1]\n";
print "Array2: @array2\n";
if ($min_pos->[1] > $#array2) {
print "Min index outside \@array2 bounds!\n";
}
else {
print 'Min index position in @array2 has value: ',
"$array2[$min_pos->[1]]\n";
}
print '-' x 60, "\n";
}
Output:
$ pm_min_mindex.pl
Array1: 1 2 3 4 5 6 7
Min value: 1
Min index: 0
Array2: a b c d e f g
Min index position in @array2 has value: a
------------------------------------------------------------
Array1: 1 2 3 4 5 6 7 0
Min value: 0
Min index: 7
Array2: a b c d e f g
Min index outside @array2 bounds!
------------------------------------------------------------
Array1: 1 2 3 4 5 6 7 0
Min value: 0
Min index: 7
Array2: a b c d e f g h
Min index position in @array2 has value: h
------------------------------------------------------------
Array1: 1 2 3 4 5 6 7 -1 0
Min value: -1
Min index: 7
Array2: a b c d e f g h
Min index position in @array2 has value: h
------------------------------------------------------------
Array1: 1 2 3 4 5 6 7 1 2 3 4 5 6 7
Min value: 1
Min index: 0
Array2: a b c d e f g
Min index position in @array2 has value: a
------------------------------------------------------------
You may find Benchmark useful for comparing the alternative solutions supplied.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: min and mindex
by tinita (Parson) on Nov 07, 2012 at 00:03 UTC
|
use List::Util qw/ reduce /;
my $min_index = reduce { $array1[$a] <= $array1[$b] ? $a : $b } 0 .. $
+#array1;
say <<"EOM";
min element: $array1[ $min_index ]
min index: $min_index
array2: $array2[ $min_index ]
EOM
| [reply] [Watch: Dir/Any] [d/l] |
Re: min and mindex
by jwkrahn (Abbot) on Nov 07, 2012 at 05:11 UTC
|
$ perl -le'
my @array1 = (1,2,3,4,5,6,7);
my @array2 = ("a","b","c","d","e","f","g");
my ( $min, $min_index ) = ( $array1[ 0 ], 0 );
for my $index ( 1 .. $#array1 ) {
if ( $array1[ $index ] < $min ) {
( $min, $min_index ) = ( $array1[ $index ], $index );
}
}
print $min;
print $min_index;
'
1
0
| [reply] [Watch: Dir/Any] [d/l] |
Re: min and mindex
by jaredor (Priest) on Nov 08, 2012 at 08:28 UTC
|
#!/usr/bin/env perl
use Modern::Perl;
my ($c, $d, $i) = ([qw(7 5 3 0 9 18 12)], [qw(a b c d e f g)], 0);
say $d->[[(sort {$a->[0]<=>$b->[0]} map {[$_,$i++]} @{$c})]->[0][1]];
| [reply] [Watch: Dir/Any] [d/l] |
|
++ I like your thinking, jaredor!
So, what's the rules of this drinking game? No doubt I lost points when I failed to utter the incantantion "Schwartzian transform" while coding:
my $min_pos = (
sort { $a->[0] <=> $b->[0] } map { [$_ => ++$pos] } @array1
)[0];
# do useful stuff
print ... $array2[$min_pos->[1]]
OK, I've downed a large Scotch. Your turn. :-)
| [reply] [Watch: Dir/Any] [d/l] |
|
Wait, what?!
*I* don't get to drink because you didn't say the magic words, but *you* do? I need to rethink the rules to this game....
... but then it is a technical fault that I didn't grok that at the core of your masterful schooling on question posting, problem analysis and solution testing was The Schwartzian ... so okay, I owe you a point or a pint, whichever you prefer.
Actually, you caught me in a minor sin, since I think "reduce" (++tinita) would be what I would use for the problem as stated (sort of like spinning a log on a lathe to get a toothpick). So I posted an answer which wasn't a great answer for the question, but allowed me to be a wee bit cheeky for my own amusement.
The "drinking game" is just something I do to keep myself engaged with the site content and is just a variant of what some people do to keep awake in meetings: See if you can predict a response. Successful prediction? Assess whether it was necessary or gratuitous. Gratuitous? Point! Take a drink. For PM my rubric is - Is the answer not wrong, but not quite right?
- Could the answer have been relatively easy to demonstrate with code, but wasn't?
- Does the answer seem to be more of an homage to the hive mind rather than a sincere effort to educate or illuminate?
(Now you see why I felt compelled to add working code to my snarky comment.)
This game is not for everyone: According to a thread I read a while back, sundialsvc4 would have destroyed BrowserUK's liver years ago. ;-)
| [reply] [Watch: Dir/Any] |
|
|