Re: How to get the index of smallest whole number in an array?
by kcott (Archbishop) on Jul 01, 2018 at 05:58 UTC
|
G'day sohamsg90,
Welcome to the Monastery.
I'm not really trying to nitpick;
however, simply saying you wanted the index of the smallest "non-negative integer",
would have precluded the need to provide a definition of what you meant by "whole numbers"
— which, incidentally, differs from what is generally understood by that term
(e.g. -5 is a whole number; -0.5 isn't) —
and made the whole thing less confusing.
I had to read it twice to make sure I understood what you were getting at.
You've added two negative integers to your test data: that's good.
However, you don't have any non-integer values to test: that's less good.
The following one-liner includes fractional test values and code to handle them.
$ perl -E 'my @x = qw{3 4 71 1 -598 -100293 0.5 -0.5}; say +(sort { $a
+->[1] <=> $b->[1] } map $x[$_] >= 0 && $x[$_] == int $x[$_] ? [ $_ =>
+ $x[$_] ] : (), 0 .. $#x)[0][0]'
3
Well, that was my actual test.
Here it is again, in a somewhat more readable format.
$ perl -E '
my @x = qw{3 4 71 1 -598 -100293 0.5 -0.5};
say +(
sort { $a->[1] <=> $b->[1] }
map $x[$_] >= 0 && $x[$_] == int $x[$_]
? [ $_ => $x[$_] ]
: (),
0 .. $#x
)[0][0]
'
3
I also tested this with the first element of @x changed from 3 to 0.3,
and also changed to -0.3. The result was the same for all three runs.
You'll note that the general approach is similar to some other solutions already posted.
| [reply] [d/l] [select] |
|
|
Not nitpicking either, but consider that the OP may not be an English native speaker. In a number of languages, integer is translated by something meaning "whole number." For example: número entero in Spanish and nombre entier in French. Granted, Perl Monks is an English-language forum, but it is attended by many people whose mother-tongue is not English.
| [reply] |
|
|
| [reply] [d/l] |
|
|
|
|
G'day Laurent,
We've always got along well in the past, so I won't automatically assume this was intended as a personal attack.
Unfortunately, what you've written comes across as arrogant: something I never find to be acceptable.
You presumed to know what I hadn't considered;
you presumed to tell me what to consider;
and, to top it all off, you presumed to instruct on the makeup of the Monastery.
I'm hoping your post was simply poorly worded.
| [reply] |
|
|
|
|
|
|
|
|
|
|
|
What does the empty list :() mean there?
| [reply] |
|
|
map $x[$_] >= 0 && $x[$_] == int $x[$_]
? [ $_ => $x[$_] ]
: (),
- where the current element of the @x array is tested the see if it is greater or equal to zero and if it is a whole number. If true an anonymous array is passed to the sort routine, if false then an empty list (i.e. nothing) is passed. This construct operates pretty much like grep to filter out any values that don't satisfy the conditions.
| [reply] [d/l] [select] |
|
|
The explanation by ++JohnGG pretty much nails it.
I might just add, by way of clarification of:
"This construct operates pretty much like grep to filter out any values that don't satisfy the conditions."
grep passes on its arguments unaltered if they satisfy the condition in BLOCK or EXPR:
$ perl -E 'say for grep length, qw{x y z}'
x
y
z
map, on the other hand, passes on whatever the BLOCK or EXPR evaluates to for each argument:
$ perl -E 'say for map length, qw{x y z}'
1
1
1
You may already be aware of this;
however, I thought it was worth pointing out:
another reader may not be fully across this distinction.
| [reply] [d/l] [select] |
Re: How to get the index of smallest whole number in an array?
by tybalt89 (Monsignor) on Jun 30, 2018 at 23:38 UTC
|
#!/usr/bin/perl -l
# https://perlmonks.org/?node_id=1217669
use strict;
use warnings;
my @array = ('3','4','71','1', '-598', '-100203');
my ($answer) = map $_->[0],
sort { $a->[1] <=> $b->[1] }
grep $_->[1] >= 0,
map [ $_, $array[$_] ], 0 .. $#array;
print $answer;
| [reply] [d/l] |
|
|
c:\@Work\Perl\monks>perl -wMstrict -le
"my @ra = qw(13 4 71 2 -598 -100203);
;;
my ($i_lwn) =
map $_->[0],
sort { $a->[1] <=> $b->[1] }
map { $ra[$_] >= 0 ? [ $_, $ra[$_] ] : () }
0 .. $#ra
;
;;
if (defined $i_lwn) {
print qq{\$ra[$i_lwn] == lwn $ra[$i_lwn]};
}
else {
print 'no lowest whole number in array';
}
"
$ra[3] == lwn 2
Update: This approach returns the lowest index of more than one LWN in an array (assuming sort is stable, which it is IIUC the documentation). I'm not sure what the simplest approach to changing this code to obtain the highest index of multiple LWNs would be. I've tested it only partially, but it may be as simple a putting a reverse call in front of the 0 .. $#ra expression at the bottom of the map stack.
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
|
johngg@abouriou ~/perl/Monks $ perl -Mstrict -Mwarnings -E '
my @arr = ( 3, 4, 71, 1, -598, -100203 );
say for (
sort { $arr[ $a ] <=> $arr[ $b ] }
grep { $arr[ $_ ] >= 0 }
0 .. $#arr
)[ 0 ];'
3
| [reply] [d/l] |
|
|
my @arr = ( 3, 4, 71, 1, -598, -100203 );
say for (
sort { $arr[ $a ] <=> $arr[ $b ] }
grep { $arr[ $_ ] >= 0 }
0 .. $#arr
)[ 0 ]; # okay. what's with the [ 0 ] ??????
I really want to know!
$state{tired}?sleep(40):eat($food);
| [reply] [d/l] [select] |
|
|
|
|
|
|
Re: How to get the index of smallest whole number in an array?
by hda (Chaplain) on Jul 01, 2018 at 09:59 UTC
|
Interesting problem and discussion. I have little to add to what has already been said, but wanted to note that a solution to the problem of finding the index of the minimum in an array is conveniently implemented in Perl Data Language (PDL) with the minimum_ind function.
From the manual:
Module PDL::Ufunc
minimum_ind
Signature: (a(n); indx [o] c())
Like minimum but returns the index rather than the value
Output is set bad if all elements of the input are bad, otherwise
+the
bad flag is cleared for the output piddle.
So, in principle, assumming you already have an array @array you could do:
use PDL;
my $piddle = pdl @array;
my $index_minimum = minimum_ind $piddle;
say $index_minimum;
You could try to reduce your problem so you can use a minimum_ind approach, for example, if you have negative numbers you could convert them to NaN or take abs and make them positive, whatever is important or relevant in your context. | [reply] [d/l] [select] |
Re: How to get the index of smallest whole number in an array?
by AnomalousMonk (Archbishop) on Jun 30, 2018 at 23:20 UTC
|
c:\@Work\Perl\monks>perl -wMstrict -le
"my @ra = qw(12 -3 4 71 -11 -598 -100203);
;;
my $i_min;
;;
$ra[$_] >= 0 and
(! defined($i_min) or $ra[$_] < $ra[$i_min]) and
$i_min = $_ for 0 .. $#ra;
;;
if (defined $i_min) {
print qq{i of min lwn ($ra[$i_min]) == $i_min};
}
else {
print 'no lowest whole number in array';
}
"
i of min lwn (4) == 2
(There may be specific utilities for this purpose in List::Util or the older List::MoreUtils.)
Update: This approach returns the lowest index of more than one LWN in an array. To obtain the highest index of multiple LWNs, change the < (less than) comparison in the
(! defined($i_min) or $ra[$_] < $ra[$i_min])
term to <= (less than or equal):
(! defined($i_min) or $ra[$_] <= $ra[$i_min])
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
Re: How to get the index of smallest whole number in an array? (Simplified)
by BrowserUk (Patriarch) on Jul 01, 2018 at 06:25 UTC
|
my @array = ('3','4','71','1', '-598', '-100203');
print reduce{ $a = $b if $array[$b] >=0 and $array[$b] < $array[$a]; $
+a } 0 .. $#array;;
3
Or more simply: print reduce{ $array[$b] >=0 && $array[$b] < $array[$a] ? $b : $a } 0
+.. $#array;
Bad data -- ie. empty array, or all negatives -- returns undef. Doesn't check values are integer.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
In the absence of evidence, opinion is indistinguishable from prejudice.
Suck that fhit
| [reply] [d/l] [select] |
|
|
all negatives -- returns undef
No you get 0 with all negatives, since the first thing reduce does is set $a to the first value in the list. Though there is more than one way to solve this, I didn't find a one that doesn't involve re-checking $a on each iteration.
| [reply] |
Re: How to get the index of smallest whole number in an array?
by mr_ron (Deacon) on Jun 30, 2018 at 23:19 UTC
|
Crossposted to StackOverflow. Crossposting is acceptable, but it is considered polite to inform about it, so that efforts are not duplicated.
| [reply] |
|
|
| [reply] |
|
|
It was posted to StackOverflow. QueryXchange is just a site that copies its content (probably to attract ad views?).
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] |
Re: How to get the index of smallest whole number in an array?
by bliako (Abbot) on Jul 02, 2018 at 15:54 UTC
|
What I find interesting, and I hope I am not out of my depth here, please correct, is that in one of the four* (?) approaches to a solution, the so-called Schwartzian transform (ST) is used. I think (as I learned about this trick not that long ago) I have spotted ST on tybalt89's, kcott's and AnomalousMonk's solutions.
What I mean is that sort() is passed something different than just the original array or just its indices in the form of additional/pre-processed information. In this case it is the index of each element *as well* as its value in the form of a tuple-ref. E.g. where map passes on to sort [ $_ => $x[$_] ] or () (another trick I learned when you want map to filter(=grep) too). And so, sort does not have to constantly ask for $arr[$a], instead it is given this value and does $a->[1] (which is comparable in overhead but let's ignore this for the sake of argument).
On the other hand, johngg manages without ST because it passes only the index of each element after filtering out non-whole numbers. And so sort() does this: $arr[$a] <=> $arr[$b].
I am not posting any benchmarks because they are totally irrelevant as this is a pet-scenario toy problem.
Now, consider that the problem was the following: For the same array, find the index of the element with the highest prime factor.
This is a blindingly obvious case for the use of ST because there is no contest between:
sort { $a->[1] <=> $b->[1] }
map { $arr[$_] >= 0 ? [ $_, max_prime_factor($arr[$_]
+) ] : () }
0 .. $#arr
and
sort { max_prime_factor($arr[$a]) <=> max_prime_factor
+($arr[$b]) }
grep { $arr[ $_ ] >= 0 }
0 .. $#arr
----
four* : 1) swartzian map/sort, 2) non-swartzian map/sort, 3) List::Util et al, 4) PDL
| [reply] [d/l] [select] |
|
|
| [reply] |
|
|
| [reply] |
|
|
Now that you mention it I agree with you, though I have not realised it earlier. Sorting is an overkill when just min value is required. But hey we cover every angle in our homework service :)
In which case your List::Util::reduce solution or a basic min-find will suffice:
$idx = $arr[0];
for(0..$#arr) {
$idx = $_ if( ($arr[$idx]<0) || (($arr[$_] >= 0) && ($
+arr[$_] < $arr[$idx])) )
}
| [reply] [d/l] |
|
|
|
|
|
|
|
|
Re: How to get the index of smallest whole number in an array?
by AnomalousMonk (Archbishop) on Jul 02, 2018 at 21:03 UTC
|
What the heck... Yet Another non-O(n), sort-based solution, this one using a Guttman-Rosler transform (GRT).
c:\@Work\Perl\monks>perl -wMstrict -le
"my @ra = qw(12 -3 4 71 5 -11 -0.99999 -598 -100203 0.99999 4);
;;
my ($i_lnn) =
map unpack('x[N] N', $_),
sort
map { $ra[$_] >= 0 && $ra[$_] == int($ra[$_]) ? pack('N N', $ra[$_]
+, $_) : () }
0 .. $#ra
;
;;
if (defined $i_lnn) {
print qq{\$ra[$i_lnn] == lowest natural number $ra[$i_lnn]};
}
else {
print 'no lowest natural number in array';
}
"
$ra[2] == lowest natural number 4
Now with more fraction rejection. Still not to be preferred, in very general terms, to an O(n) solution IMHO. Still returns the lowest index of multiple LNNs (update: but a small change will return the highest). (I've started referring to these numbers as "lowest natural numbers" in deference to the N-pairs in the pack/unpack templates.) If you object to all the evaluations of $ra[$_] in the first map statement, try
map { my $e = $ra[$_]; $e >= 0 && $e == int($e) ? pack('N N', $e, $_) : () }
instead (tested), but I doubt there'll be much difference.
Update 1: Of course, this will only handle natural numbers in the range of a 32-bit N template specifier. 64-bit Perls have 64-bit Q specifiers. (Update: johngg points out that a big-end enforced Q> (note > modifier) is necessary for proper GRT sorting. I can't test this ATM.)
Update 2: Here's another, semi-tested variation to play around with:
map $ra[$_] >= 0 && $ra[$_] == int($ra[$_]) && pack('N N', $ra[$_], $_) || (),
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
Re: How to get the index of smallest whole number in an array?
by sohamsg90 (Initiate) on Jul 02, 2018 at 18:16 UTC
|
Thank you all for helping me out. I really appreciate the different answers, approaches and the detailed explanation provided along with it. I apologize if I was unable to make my question clear enough. I'm new at programming and this was not for any assignment or homework. I was stuck at this for a while and was unable to find any other posts related to the specific problem. Thank you again. Have a great day. | [reply] |
Re: How to get the index of smallest whole number in an array?
by Anonymous Monk on Jul 02, 2018 at 16:05 UTC
|
If you want your homework done for you, you've come to the right place.
| [reply] |