Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

This is relatively can be done by looping through values of any array and count how many of array elements are greater than $x and then calculate the percentage as follow. I am just wondering if there is another way to avoid the looping.

#!/usr/local/bin/perl use strict; my $y= 10; my @array =(1, 4, 5, 7, 8, 9, 10, 20, 30, 40, 60); my $greater = 0 ; if(my $y >= 1){ foreach my $elem (@array){ if ($elem > $y){ $greater++; } } my $pecentgreater = $greater /(scalar @array) *100; print "Percent Greater Than y = $pecentgreater\n";

Replies are listed 'Best First'.
Re: Calculated % of data greater than $x in an array
by ikegami (Patriarch) on Mar 05, 2010 at 18:21 UTC

    I am just wondering if there is another way to avoid the looping.

    We often get this kind of question, and it make no sense. They want to execute the same code repeatedly (in this case, checking if an element is greater than $x), and they want to do it without looping. The problem is that executing the same code repeatedly is the very definition of looping. What does looping mean to those people?

    True, some say they want to avoid a specific kind of loop, but they never say what about that kind of loop they are trying to avoid. I find it hard to believe it's because they don't like the spelling of the keyword.

      I have wondered the same thing often. Maybe Corian can address your comment and speak for all of the loop-haters out there.

        Whoops. Twice, I thought Corian was the originator of the question. Sorry about that. I should sign up for an account so I can correct my stupidity in the future.
Re: Calculated % of data greater than $x in an array
by toolic (Bishop) on Mar 05, 2010 at 18:25 UTC
    Assuming your input array is sorted numerically (as in your code), you can use the firstidx function from List::MoreUtils to get the index of the first element greater than a specified value. This function will stop looking through the array as soon as the condition is met.

    If your input array is not ordered, you must inspect every element. grep is very handy for that task.

    use strict; use warnings; use List::MoreUtils qw (firstidx); my $y = 10; my @array = (1, 4, 5, 7, 8, 9, 10, 20, 30, 40, 60); my $tot = scalar @array; my $i = firstidx { $_ > $y } @array; printf "%d%%", 100*($tot-$i)/$tot; __END__ 36%
Re: Calculated % of data greater than $x in an array
by BrowserUk (Patriarch) on Mar 05, 2010 at 18:22 UTC
    @array =(1, 4, 5, 7, 8, 9, 10, 20, 30, 40, 60);; $n = 5; printf "%.2f%% of the array is greater than %d\n", grep({ $_ > $n }@array) / @array *100, $n;; 72.73% of the array is greater than 5 $n = 20; printf "%.2f%% of the array is greater than %d\n", grep({ $_ > $n }@array) / @array *100, $n;; 27.27% of the array is greater than 20 $n = 0; printf "%.2f%% of the array is greater than %d\n", grep({ $_ > $n }@array) / @array *100, $n;; 100.00% of the array is greater than 0
Re: Calculated % of data greater than $x in an array
by ack (Deacon) on Mar 05, 2010 at 20:59 UTC

    If all you're interested in is a short way (without having to type in the lines of a loop structure), then the following is a way to do it (there may be shorter ways):

    #!/usr/bin/perl use strict; use warnings; my $y= 10; my @array =(1, 4, 5, 7, 8, 9, 10, 20, 30, 40, 60); my $greater = 50 ; my $num = scalar(@array); my $percent = (scalar(grep{$_ > $greater} @array)/$num)*100; print "Percent of \@array's $num items greater than $greater is $perce +nt%\n"; exit(0);

    Of course you can shorten it even more by putting the scalar(@array) directly in the division in plac of the $num that I use. I did it that way so that I could report the number of elemnts in the array in the print statement.

    But overall I completely agree with ikegami in as much as several folks of late have asked how to things 'without looping' but that reqire 'looping' to accomplish. The answer, in general, is that 'you can't'. So I have been interpreting the questions to mean either (1) 'how do I do it without having to type in the loop structures' and/or (2) 'Is there a way that perhaps the compiler (interpreter) can do it for me more efficiently'.

    I don't knowwhat the OP was looking for, but hopefully we answered the question. Good luck,

    ack Albuquerque, NM
Re: Calculated % of data greater than $x in an array
by Corion (Patriarch) on Mar 05, 2010 at 18:03 UTC

    Why do you have this line in your code?

    if(my $y >= 1){

    Other than that, there is little to improve your code. I would sort the list first, and stop looking at the list elements once I've found the first element that is greater than my target $y, but that's it.

      Sorting is always at least O(n log n). Checking each element is O(n). You don't save anything here by sorting.

      Corion: why are you trying to avoid looping? Even if you write some code to solve this problem that doesn't look like it's looping, trust me, it is.

        O() only speaks of scalability. It doesn't show that nothing was saved. It wouldn't surprise me to find that Corion's approach is faster, even for long lists. Besides, speed is not the only factor that affects the choice of tools. That said, I don't see the point of sorting here.

        I know that you don't save much by sorting instead of looping through the whole array, but if you want other ranks/n-tiles than just the one, operating on a sorted list is easier.