Question

Using Perl, I wish to find the last element that is defined in an array.

So far I have the following:

#generating array
$array[100] = (undef);
$array[$columns[1]-1] = $columns [2];

#finding the last element that is defined
for ($i=100; $i>=0; $i--) {
    if (($array[$i] != undef) && (!defined($lastdef)) ){
        $lastdef=$i;
    }
}

I'm not sure why this is not working. Any suggestions to improve, using Perl?

Was it helpful?

Solution 4

You need to start from 99 as 100 elements array has indexes: 0 .. 99. And break the loop as soon as you find the element:

#!/usr/bin/perl

use strict;
use warnings;

my @array = (1, 2, undef);

my $lastdef;
for (my $i = $#array; $i>=0; $i--) {
    if (defined($array[$i])){
        $lastdef=$i;
        last;
    }
}

print $lastdef;

prints: 1

OTHER TIPS

I'm not sure why this is not working. Any suggestions to improve, using Perl?

The reason you don't know why it is not working is because you are not using

use warnings;

If you had, you would have been told:

Use of uninitialized value in numeric ne (!=) at ...

Because != is the numeric inequality operator, and it will convert its parameters to numbers. If you do not have warnings turned on, this will silently convert undef to 0. Needless to say, having warnings turned on is a very good thing, so that you do not make mistakes like this.

It is this line:

if (($array[$i] != undef) ...

That should be

if ((defined($array[$i]) ...

Because it is the defined function that checks a value for definedness. It is an odd mistake to make, since you even use that same function on the same line.

Also, you can make this simpler by doing

if (defined($array[$i])) {
     $lastdef = $i;
     last;
}

last will here end the loop when the first undefined value is found.

You should also know that you can use a non-hardcoded max value on your loop condition:

for (my $i = $#array; $i >= 0; $i--) {

$#array contains the number of the highest existing index in your array.

You could be more concise by using a List::Util function. This will find the last element in the array that is defined, but not the index of it. To find the index of it, you can do something similar to this answer using defined instead of eq.

use List::Util qw(first);

my $lastdef = first { defined($_) } reverse @array;

The following is a little ugly and obscure (compared to @TLP's excellent answer), but it was fun to write:

#!/usr/bin/env perl

use strict;
use warnings;

use feature 'say';

for my $i (0, 1) {
    my $array = generate_array(8, $i);
    say join ' ', map $_ // '_', @$array;
    say index_of_last_defined_element($array);
}

sub index_of_last_defined_element {
    my $x = $#{ $_[0] };
    my $v = $_[0]->[$x];
    return $x if defined($v) or $x < $[;
    $#{ $_[0] } -= 1;
    goto &index_of_last_defined_element;
}

sub generate_array {
    my $size = shift;
    my $array = [ (undef) x $size ];
    shift or return $array;
    $array->[rand $#$array] = 'x';
    return $array;
}

Output:

_ _ _ _ _ _ _ _
-1
_ _ _ _ _ x _ _
5

Of course, this is all a bit silly. You should use List::MoreUtils::last_index:

use feature 'say';
use List::MoreUtils qw(last_index);

for my $i (0, 1) {
    my $array = generate_array(8, $i);
    say join ' ', map $_ // '_', @$array;
    say last_index { defined($_) } @$array;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top