I hope I'm doing this right...

Hereís a proposal for Perl Golf. I have a solution, but after seeing some of the code routinely produced on this site, Iím sure itís not the best.

Given: A set of files in a directory, all with similar filenames, i.e., bar0001.jpg, bar0002.jpg, etc.. Some of you may have directories like this, I believe I have a few myself.

Goal: Write a program that identifies all the missing files in a sequence of the files(not necessaarily all inclusive). It should accept input from the user in either numeric (i.e. 0 and 50) or stringwise (i.e., 0000 and 0050) or a combination of the two.

For an added challenge, figure out what to do if the user inputs a string too big for the comparison (i.e., 00000 rather than 0000). I didnít do this in my solution, but Iíd be very interested in seeing a good way to do it.

In keeping with how I understand the typical Perl Golf proposal to be, I will wait two days before posting my solution. If Iím incorrect in this assumption, let me know and Iíll post it right away. Not that my solution us likely to compare, but it does work. (As opposed to another post I made, that I now wish I hadn't made)


Replies are listed 'Best First'.
Re: Perl Golf Proposal
by chipmunk (Parson) on May 23, 2001 at 06:53 UTC
    Keeping in mind that this golf challenge asks for a program rather than a subroutine... :)

    48 characters:

    #!perl $m=pop;for$"(pop..$m){$_="@ARGV";-e||warn"$_\n"}
    example usage: perl bar .jpg 0000 0050

    Hurrah for the range operator and magical auto-increment!

    As best I can figure it, the only way to accurately accomplish the bonus (checking for a comparison string that's too big) is to check all the files in the directory. Otherwise there could be one file in there with a unique part of the right length.

      You forgot the input can be (eg) 50 or 0050 and that the filenames contain other text, but otherwise, nice idea :) ++

      cLive ;-)

      PS, if you look at mine, it is a prog, not a sub :)) I just began with the sub so i didn't have to explicitly call it with & or () later on when assigning $c & $d.

        I plead innocent on both counts.

        I wrote the program so it would work for any incrementing filenames, such as:

        • bar0.jpg, bar1.jpg, ..., bar50.jpg
        • bar000.jpg, bar001.jpg, ..., bar050.jpg
        • or even: barA.jpg, barB.jpg, ..., barZ.jpg
          (although that one's just a fortunate coincidence of using the range operator :)
        I guess that may not be what sharle intended, but it makes the program so much more useful!

        As for the other parts of the filename, those are the first and second arguments to the program.

        P.S. Heh, yours is a program. Very sneaky of you! :)

Re: Perl Golf Proposal
by cLive ;-) (Prior) on May 23, 2001 at 06:06 UTC
    sub i{$_=<>;chop;if(/^\d{1,4}$/){return sprintf("%04d",$_)}print"!\n"; +&i}$c=i;$d=i;for($c..$d){$_="bar$_.jpg";print"$_\n"unless(-e)}

    Enter first then last in sequence. no check made that second number is larger than first (not in challenge :))

    ! means re-enter digit

    131 chars (includes 'bonus' challenge).

    Hmmm, that was fun :)

    cLive ;-)

    Update: if larger strings *are* valid as long as they are numerically correct, the above needs amending to:

    sub i{$_=<>;chop;if(/^\d+$/&&$_<10000){return sprintf("%04d",$_)}print +"!\n";&i}$c=i;$d=i;for($c..$d){$_="bar$_.jpg";print"$_\n"unless(-e)}

    adding another 6 chars...

Re: Perl Golf Proposal
by mr.nick (Chaplain) on May 23, 2001 at 06:06 UTC
    Okay, here's my very cheesy entry. It actually doesn't follow the rules, but it's the best I could do ;) I at least followed the intent (on finding missing files).

    You pass missing a list of files (which must be presorted :) and it will return all the missing ones. No other options are available, but in the case of a directory of files, it works.

    sub missing { for$x(($_[0]=~/(.+)\..+/)[0]..($_[$#_]=~/(.+)\.(.+)/)[0]) {push@x,"$x.$2" unless grep$x eq(/(.+)\..+/)[0],@_};@x; } print missing qw (bar001.jpg bar002.jpg bar010.jpg);
    That's 111 characters. It's sloppy, it's very confined and it's not compliant. But shoot, I couldn't do it correctly. I should add, however, that mine version doesn't require the filenames to start with "bar" or end with ".jpg". They can be anything. The missing function properly handles most things.
Re: Perl Golf Proposal
by sharle (Acolyte) on May 24, 2001 at 08:05 UTC
    At a couple of people's suggestion, I'll post my solution. First, this problem arose because of large file collections posted on certain, ahem, alt.binaries newgroups. If you have a large number of files in a particular series, it can be rather cumbersome to cull through the directory and find the missing files, so I developed the following program to solve my problem.
    It's probably a perlmonks sin to use Perl for such nefarious purposes, but I tried it in a couple of other languages and nothing gave me the ease of string checking against numeric values that Perl does, so of necessity was born another Perl convert.
    What I meant by numeric or stringwise entry is that when the program asks for the search start and end, it should accept 0000 or 0, and for the end of the search range, should accept 0050 or 50. (The files tend to be named with leading zeros)
    Anyway, here's the code, complete with my simplistic comments:

    #!/usr/bin/perl -w # Stan Harle # # use strict; # Identify variables in advance (good practice!) my ($location, $L, $el, $el2, @srtlist, @filelist, $filcheck); my ($i, $p, $pre, $post, $strt, $ensr, $srtval, @filenames, $filenames +); my ($strt1, $ensr1); # Input the test directory into variable $location STARTING: print"Input the test directory\n"; chomp($location = <STDIN>); # Change directories to target directory chdir $location || muckup(); # Read file list into directory variable @filelist opendir (DIR, "$location"); @filelist = grep(!/^\.\.?$/, readdir (DIR)); closedir (DIR); @srtlist = sort @filelist; # Sort the values in the directory list array # Enter starting number for search print"What number do you want to start from\?"; chomp($strt = <STDIN>); $strt1 = $strt; # Enter Ending number for sequence of sort print"What number do you want to end at\?"; chomp($ensr = <STDIN>); $ensr1 = $ensr; # Loop to fill array with 1s to block out unneeded values for ($p = 0; $p <= $strt; $p++) { $filenames[$p] = 1; } # Loop to fill array with found and missing filenames for ($p = $strt; $p <= $ensr; $p++) { # This prevents an uninitialized place in case of no find $filenames[$p] = 0; foreach (@srtlist) { if ((/$strt1/) || ( (/$p(?![0-9])/) && (substr($',0,1) !~/ +[0-9]/) && (substr($`,-1,1)!~/[0-9]/)) ) { $filenames[$p] = 1; $pre = $`; $post = $'; } } $strt1++; } # Reinitialize $p and $i $p=0; $i=0; # Print out names of missing files foreach (@filenames) { if ($_ eq 0) { print "$pre$p$post\n"; $i++; # $i is just a checker for no missing files, +does nothing else } $p++; } print "\nNo Missing Files\!\n" if ($i eq 0); # Check for no mi +ssing files # Subroutine in case of user typos sub muckup { print"$location doesn't work.\n\n Did you mistype\?\n\n"; goto STARTING; }
    which gave rise to the following solution:
    This program is run with the start line
    perl /e/test 0000 0050

    my($L,$b,$d)=@ARGV;opendir(DIR,"$L");@s=grep(!/^\.\.?$/,readdir(DIR)); +closedir(DIR);$b1=$b;for($p=$b;$p<=$d;$p++){$i=0;foreach(@s){$_=$s;if +((/$b1/)||((/$p(?![0-9])/)&&(substr($',0,1)!~/[0-9]/)&&(substr($`,-1, +1)!~/[0-9]/))){$i =1;}}print"$p\n"if($i eq 0);$b1++;}

    271 characters.
    While working out the golf solution I figured out that sorting the array isn't necessary, and neither is the change to the target directory, which gives even beginners reason to golf. :)

    I apologize for not defining the parameters and exact nature of the problem more exactly, and I'll try to do better next time.