This is more of a "I am interested if it's possible" than a "I really need it" question, but anyway: I know if I want the smallest value in a list using a custom function comparison, I can do it easily with List::Util::reduce
.
my $biggest = reduce {comparison($a, $b) ? $b:$a} @myArray;
But if I want the two biggest values in that array? Again, with just one traversal of the array.
I can do it by writing a for
loop, but I would really like a more perlish one-liner.
Edit: By just one traversal of the array, I meant that the computational complexity won't be bigger than O(n)
. Sorting all the articles is not that effective since I don't need everything sorted, just the two biggest values.
But I am probably asking too much :)
A complexity measure quantifies the use of a particular computational resource during execution of a computation. The two most important and most common measures are time, the time it takes a program to execute, and space, the amount of store used during a computation.
We are given an integer array of size N or we can say number of elements is equal to N. We have to find the largest/ maximum element in an array. The time complexity to solve this is linear O(N) and space compexity is O(1).
Slowest = O(nn ) – Because of its time complexity, the most time-consuming function and the slowest to implement.
O(N²) — Quadratic O(N²) represents the complexity of an algorithm, whose performance is proportional to the square of the size of the input elements. It is generally quite slow: If the input array has 1 element it will do 1 operation, if it has 10 elements it will do 100 operations, and so on.
To find the max two values of a list, you can either loop across the values with two variables to hold the maximums:
my @list = qw(3 1 2 5 9 7 8 6 4);
my ($x, $y) = (0, 0);
($x, $y) = $_ > $x ? ($_, $x) :
$_ > $y ? ($x, $_) : next for @list;
say "$x $y"; # '9 8'
or you can use a fold to reduce the list:
use List::Util 'reduce';
my $max = reduce {
$b > $$a[0] ? [$b, $$a[0]] :
$b > $$a[1] ? [$$a[0], $b] : $a
} [0, 0], @list;
say "@$max"; # '9 8'
The two solutions are equivalent, the first is procedural in nature and requires external state, the second is functional and does not. The first is likely faster since it does not create any internal arrays for storage. Each only loops over the list once, so both are O(n)
There's always (sort { compare($b, $a) } @array)[0 .. 1]
-- which works for any number of outputs you want, as long as you make sure not to try to take more items than exist in @array
. The downside is that it does more work in sorting the whole array than it really has to.
You can also extend the reduce
solution to keep any number of largest values seen so far, but I haven't yet been able to write a version of that that still has the "one-liner" feel :)
my @biggest_two = ( sort { $b <=> $a } @myArray )[0..1]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With