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

i know how to find out if x is an element in an array, but once found, how can i remove it from the list?

Replies are listed 'Best First'.
Re: removing x from a list
by Sherlock (Deacon) on Apr 20, 2001 at 07:30 UTC
    If you can determine the index of the element within the array, you can use the splice command to remove the element from the array, like this:

    splice(@array, $indexToRemove,1);
    This will remove 1 element from @array at the index $indexToRemove. If you'd like more explanation, go to: How do I completely remove an element from an array?

    - Sherlock
Re (tilly) 1: removing x from a list
by tilly (Archbishop) on Apr 20, 2001 at 21:00 UTC
    People are working too hard on this!

    Suppose you don't want your array to have undef elements:

    @array = grep {defined $_} @array;
    Put more complex tests in as desired...
(zdog) Re: removing x from a list
by zdog (Priest) on Apr 20, 2001 at 07:30 UTC
    You can do this:

    for (0 .. $#array) { if ($x == $array[$_]) { splice (@array, $_, 1); last; } }

    Zenon Zabinski | zdog | zdog7@hotmail.com

      hrm . . . it does not seem to be working . . . perhaps some code is in order.

      opendir(SONGS, 'd:\my files'); @songs = readdir(SONGS); @songs = sort @songs; open(LIST, ">mp3.html"); print LIST<<End_Of_Html; Content-type: text/html <html> <head> <title>My MP3's</title> <center> Just a note of forwarning, there are over one thousand in here, so if +you intend to go through the whole thing, it may take you awhile. If + you want any of these, just ask and i can send it. Unfortunately i +have a very small hard drive and can't fit them all on this drive. <br> </center> End_Of_Html $x = '.'; $y = '..'; for (0 .. $#array) { if (($x == $songs[$_]) or ($y == $songs[$_])) { splice (@songs, $_, 1); last; } } print LIST join("<br>", @songs); close(LIST);
      basically, i'm trying to scan the folder with my mp3 archive and make a list of all of them, but exclude the directory special charcters '.' and '..' it isn't giving me any error or anything, it just keeps including the special characters.

        Sometimes it's easier just to say what you will allow, and exclude everything else, than to exclude a multitude of patterns. You're likely to miss something in the process. This statement holds true in everything from security, user input validation, and to your specific problem.

        Since you are making a list of mp3 files, you could only allow files with the extension .mp3 to get into your @songs array, and exclude all others.

        Also, it's usually a good idea to sort after you have removed as much as possible from your list. Why bother to sort something that could have less elements in the near future? =) The original sample code you posted reads the directory, copies the file names into an array, then sorts the array and copies it back again to the same array.

        Of course, if efficiency was really important, I wouldn't have used grep or a regex, but I think this illustrates the point:

        #!/usr/bin/perl -wT use strict; use constant SONG_DIR => 'd:\my files'; opendir(SONGS, SONG_DIR) or die "could not open the ", SONG_DIR, " directory: $!"; my @songs = sort grep { /\.mp3$/ } readdir SONGS; closedir SONGS;
        It might be a lot easier if you just got what you wanted out of the readdir call first:
        opendir (SONGS, $song_dir); @songs = sort grep { !/^\.\.?$/ } readdir(SONGS); closedir (SONGS);
        So in one line you get the sorted, filtered, directory listing. In this case, grep will only allow those array elements that are not '.' and '..' to pass through.

        Perl commands can be stacked, and the output of one flows right into the other, in a right to left manner. This means that your two statements:
        @songs = readdir(SONGS); @songs = sort @songs;
        Can actually be combined into a single equivalent one:     @songs = sort readdir(SONGS); Just as:
        $x = $y; $x = $z + $x;
        Can be converted to:    $x = $z + $y;
        Methnks File::Find will be what you need to solve your real problem. This module - part of the standard Perl distribution IIRC - is designed to go through directories looking for files that meet certain criteria.
        You have to change the $#array in the for (0 .. $#array) to for (0 .. $#songs).

        Zenon Zabinski | zdog | zdog7@hotmail.com

Re: removing x from a list
by Chmrr (Vicar) on Apr 20, 2001 at 07:30 UTC

    Please search the monastery before asking your questions. Often, if it seems like others must have worked it out before, it's a FAQ. Super Search is your friend. Anyways, I think you'll find that your first question has been answered, as has your second.

    Update: Oops! I misread your question as two. Ignore the first "answer," -- but, as stated above, splice is going to be handy.

     
    perl -e 'print "I love $^X$\"$]!$/"#$&V"+@( NO CARRIER'

Re: removing x from a list
by satchboost (Scribe) on Apr 20, 2001 at 20:09 UTC
    The following code will NOT work:
    my @array = (5, 4, 3, 2, 1); foreach (0 .. $#array) { print "$_ => $array[$_]\n"; if ($array[$_] <= 3) { print "Splicing $_ => $array[$_]\n"; splice @array, $_, 1; } }

    What happens is that (0 .. $#array) is set to (0 .. 4) at the very beginning of the list. This means that you'll be trying to access an array subscript that doesn't exist if any of your splices actually occur.

    This is actually one of the few places that a while loop is better than a foreach loop. Make the following change:

    my @array = (5, 4, 3, 2, 1); my $i = 0; SPLICER: while ($i < @array) { print "$i => $array[$i]\n"; if ($array[$i] <= 3) { print "Splicing $i => $array[$i]\n"; splice @array, $i, 1; next SPLICER; } $i++; }
    That works quite nicely.