min and mindex

 on Nov 06, 2012 at 16:45 UTC Need Help??
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";

Replies are listed 'Best First'.
Re: min and mindex
by rjt (Deacon) 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.

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.

I like this example. What would you do if the values in array1 were not unique?

Perhaps something like the following:

```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.
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();

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');
Re: min and mindex
by kcott (Chancellor) 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();
my \$min_index = \$stat->mindex();

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.

-- Ken

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
Re: min and mindex
by jwkrahn (Monsignor) on Nov 07, 2012 at 05:11 UTC
I'm try to get the min value and position in array1.

You could use a simple loop:

```\$ 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

Re: min and mindex
by jaredor (Priest) on Nov 08, 2012 at 08:28 UTC

Y'all are messing with my PerlMonks drinking game: No one said Schwartzian transform, e.g.,

```#!/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]];

++ 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. :-)

-- Ken

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

1. Is the answer not wrong, but not quite right?
2. Could the answer have been relatively easy to demonstrate with code, but wasn't?
3. 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. ;-)

Create A New User
Node Status?
node history
Node Type: perlquestion [id://1002519]
Approved by herveus
help
Chatterbox?
 [LanX]: he just read an article that the production of one battery for an e-car causes the same amount of CO2 emission like a conventional car in 200000 km [LanX]: oO [SuicideJunkie]: That's a dumb comparison. If you want to compare equivalent things, you should ask about battery+motors vs fuel tank+engine+ transmission.

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (10)
As of 2017-08-22 18:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Who is your favorite scientist and why?

Results (339 votes). Check out past polls.

Notices?