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

This question was proposed to the room and got many answered, the result of the script did not change. Maybe I can show you what's going on and what I'm trying to do.

PERL Black Book mentions you can delete $array[index], it doesn't say there are limitations or anything. It makes it sound like you can delete ANY element by doing it like this but someone in the room said otherwise. Can someone explain this to me?

I have an array with blank values and I cannot get rid of them with grep, delete splice. To see what was actually contained that was causing problems, I used print "This is what we found: \"\""; and the result comes back literally "This is what we found: "". So it's empty and/or undefined.

Things I have tried:

@n = grep $_, @n;
@n = grep defined, @n;
@n = grep defined and length, @n;
for(my $count = 0; $count < @myarray; ) { unless(defined $myarray[$count]) { splice @myarray, $count, 1; } else{ $count++ } }
my $count = -1; foreach(@myarray) { $count++; if (!defined $_) { splice(@myarray,$count); #delete $myarray[$count]; } } No matter which of these I use, when I print out the array I get a han +dful of "Use of uninitialized value at line 55". Anyone have any sug +gestions as to why these little buggers won't go away?

Replies are listed 'Best First'.
Re: Removing null values from within an array
by davido (Cardinal) on Mar 06, 2004 at 05:04 UTC
    Taking your solutions one by one:

    @n = grep $_, @n;

    This will put into @n all elements of the original @n that evaluate to true. But that means that elements whos value is 0, or "", or anything else that evaluates to false, will get skipped over. "undef" does evalute to false, by the way.

    @n = grep defined, @n

    This is what you want if all you care about is getting rid of elements whos value is undef. This will retain elements of zero value or empty strings, so long as they're not undef. I worked up several test snippets showing that this works for that type of situation. No need to show them here; it's pretty basic stuff.

    @n = grep defined and length, @n

    Here you're getting into trouble because of the low precedence of the "and" logical short circuit operator. You would be better served by using "&&" in this case. "and" binds at such a low precedence that everything to its right is no longer seen as part of the parameter list to grep. Wierd, huh? "&&" solves this problem (parenthesis placed in the right place would solve it too). But then you're going to be saying "if its value is defined and of a length greater than zero". That may be ok, or it might be better to say "@n = grep defined && $_, @n;". That way instead of testing for length, you're testing for truth.

    And I won't get into the rest of your solutions because they are too unPerlish to wade through. I think that in general you'll find it to be a good way to run amok; to try to delete array elements while iterating through the array with a C-style loop.


    Dave

Re: Removing null values from within an array
by Mr. Muskrat (Canon) on Mar 06, 2004 at 04:45 UTC

    #!/usr/bin/perl use strict; use warnings; my @array = (undef,1,undef,2,undef,3); @array = grep { defined $_ } @array; print "@array\n";

    Update: removed unnecessary $_ if

What it means to define and to delete array elements
by TomDLux (Vicar) on Mar 06, 2004 at 07:00 UTC

    It seems to me the other comments are answering a different question than the one you are asking. Or maybe I'm the one misunderstanding your question.

    Let's say you have an array which you initialize with some values:

    @values = qw( 00 11 22 33 ); use Data::Dumper; print Dumper \@values; # generates the output: $VAR1 = [ '00', '11', '22', '33' ];

    By the way, I'm cutting and pasting from my debugging session perl -d -e 1. That means I may forget the semi colon at the end of a line, you don't need them in the debugger.

    So the Array contains four values: $values[0] is "00", up to $values[3] which is "33".

    Let's suddenly create $values[6]. What do you suppose happens with the in-between array slots, for which we have not defined values? What happens with $values[4] and $values[5]?


    It may be useful to also read the system documentation on delete. Type perldoc -f delete


    This started off as a quick and easy clarification. Why is it now two hours later?

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

Re: Removing null values from within an array
by Roger (Parson) on Mar 06, 2004 at 15:54 UTC
    Guess it's time to add a map solution as well.

    my @n = array with nulls; @n = map { defined $_ ? $_ : () } @n;

Re: Removing null values from within an array
by sgifford (Prior) on Mar 06, 2004 at 20:14 UTC
    The documentation for delete says:
    Deleting an array element effectively returns that position of the array to its initial, uninitial­ized state. Subsequently testing for the same element with exists() will return false. Note that deleting array elements in the middle of an array will not shift the index of the ones after them down--use splice() for that. See the exists entry elsewhere in this document.

    So putting 4 elements in an array and deleting the middle two:

    #!/usr/bin/perl -w $arr[0]='a'; $arr[1]='b'; $arr[2]='c'; $arr[3]='d'; delete $arr[1]; delete $arr[2]; print join(" ", map { defined() ? $_ : '[undef]' } @arr),"\n";;
    is exactly the same as just not putting the middle two in to begin with:
    #!/usr/bin/perl -w $arr[0]='a'; $arr[3]='d'; print join(" ", map { defined() ? $_ : '[undef]' } @arr),"\n";
    Both produce the same output:
    a [undef] [undef] d
Re: Removing null values from within an array
by sulfericacid (Deacon) on Mar 06, 2004 at 10:17 UTC
    Wow, I surely didn't now it was this difficult to remove array elements. I thought deleting them actually removed it. But if you still haven't got it working, why not instead build a new array with just the good elements? You don't have to worry about deleting anything.
    my @original = ("", undef, "perl hungry", "", "twenty"); my @original_kept; foreach(@original) { my $what_we_removed = shift(@original); # take our first item off and +keep it if (defined $what_we_removed && $what_we_removed ne "") { push(@original_kept, "$what_we_removed"); } } print join("\n", @orignal_kept);


    "Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

    sulfericacid

      Removing array elements is easy.

      If you want to remove the value without losing the slot, use delete. If you want to eleminate the slot and value together, use splice:

      @a = qw( 0 1 2 3 4 5 6 ) # starting at position 2, delete 1 element splice @a, 2, 1 print join ", ", @a # generates the output : 0, 1, 3, 4, 5, 6

      splice() can do lots more ...see perldoc -f splice

      --
      TTTATCGGTCGTTATATAGATGTTTGCA

Re: Removing null values from within an array
by runrig (Abbot) on Mar 06, 2004 at 16:25 UTC
    You need to post a complete (but brief) example. The @n = grep defined, @n should work for what you are describing. Your examples have no input and no output, so we can not tell where you are going wrong. Mr.Muskrat's answer above is a complete example with input and output. Can you post something similar that demonstrates the problem? At a guess, maybe you have a typo and need strict.