in reply to generating unique filenames

Hello Datz_cozee75,

Here are some observations on coding style:

  1. The calling code can be reduced from 4 lines to 2:

    printf "next is %s\n", next_file($_) for qw( a.png dpq.jpg zx.png ott.jpg zzz.tiff oi.png );
  2. sub next_file { ... my @alphabet = qw/a b c d e f g h j k m n p q r s t u v w x y z/;

    creates and populates a new @alphabet on each call to sub next_file. Here is one way to avoid this:

    { my @alphabet; BEGIN { @alphabet = ('a' .. 'h', 'j', 'k', 'm', 'n', 'p' .. 'z'); +} sub next_file { ... } }

    (You could also use state, but as state variables can only be scalars, the variable would have to be an array reference, and you would then incur the additional overhead of a dereference on each access.)

  3. $previous =~ /(.*)\.(.*)/; my $word = $1; my $ext = $2;

    may be written more succinctly as:

    my ($word, $ext) = $previous =~ /(.*)\.(.*)/;
  4. $z = $z + 1; may be written more succinctly as ++$z;

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Replies are listed 'Best First'.
Re^2: generating unique filenames
by Aldebaran (Curate) on Oct 05, 2014 at 19:38 UTC

    Thanks, Athanasius, I've been trying to have @alphabet populated before I call next_file, but my caller is a hot mess. I have a main hash for this program, and what I try to do if I think data needs to be persistent over differing subroutine calls, is throw it onto the main hash. It usually starts out ugly, but eventually settles down once I've written the routines better. This is the first time I've tried to throw a reference to an array on this hash. Furthermore, I try to pass a reference to the main hash and a scalar to next_file, and what I have isn't initializing. I list all of start_magick and and then next_file to line 116 of this module, which is where stderr is telling me I'm not catching the passed variables properly.

    sub start_magick { use strict; use warnings; use 5.010; use Path::Class; use File::Copy "cp"; my ($rvars) = shift; my %vars = %$rvars; # this is supposed to be instantiated once my @alphabet = qw/a b c d e f g h j k m n p q r s t u v w x y z/; my $ref_alpha = \@alphabet; my $initial = $alphabet[0]; my $path1 = $vars{"to_images"}; my $path2 = $vars{"to_magick"}; #might need creating: my $return = mkdir($path2); say "return on mkdir is $return"; #additions to main hash $vars{"target"} = 100; #k $vars{"bias"} = 2; #k $vars{"pixel_min"} = 600; #k $vars{"previous_file"} = $initial; $vars{"ref_alpha"} = $ref_alpha; #get filenames minus directories my @basenames; opendir my $hh, $path1 or warn "warn $!\n"; while ( defined( $_ = readdir($hh) ) ) { next if ( $_ =~ m/^\./ ); say "default is $_"; push @basenames, $_; } @basenames = sort @basenames; for (@basenames){ my $file1 = file( $path1, $_ ); $_ =~ /(.*)\.(.*)/; my $ext = $2; my $word = join( '', $vars{"previous_file"}, '.', $ext ); my $next = next_file($rvars, $word); say "next is $next"; $next =~ /(.*)\.(.*)/; my $newword = $1; $vars{"previous_file"} = $newword; my $file2 = file( $path2, $word ); cp ("$file1","$file2"); } } sub next_file { use strict; use warnings; use 5.010; my ($rvars, $previous) = @_; my %vars = %$rvars; my $array_ref = $vars{"ref_alpha"};
    default is Screenshot from 2014-08-21 13:10:18.png default is Screenshot from 2014-09-25 17:14:08.png default is Screenshot from 2014-08-21 13:22:42.png default is zbears.jpg default is yjj.jpg Can't use an undefined value as an ARRAY reference at template_stuff/n +ibley1.pm line 116. $

    The loop over @basenames is this tortured munging that one resorts to when unable to pass arguments well. Thanks for your comment.

      Hello Datz_cozee75,

      Consider what the following assignments do:

      my ($rvars) = shift; my %vars = %$rvars;

      The first line shifts an argument off the call stack and copies it to the lexical variable $rvars. So far, so good. But then the second line dereferences $rvars as a hash (using the %{ ... } dereferencing syntax), and copies the contents of that hash into the new lexical hash variable %vars. From this point on, %vars is a local copy of what was in %$vars when the subroutine was called. Any changes made to %vars remain local to the subroutine, and have no effect on the contents of the original hash. So when next_file() is called, it receives $rvars as its first argument, but the hash to which that variable refers has no key named ref_alpha, so the attempt to access it on line 116 fails and produces the error message you are seeing.

      But why do you want to make a copy of the hash %$rvars? Just remove the variable %vars, and access the “master hash” directly:

      my ($rvars) = shift; ... my $path1 = $vars->{"to_images"}; my $path2 = $vars->{"to_magick"}; ...

      Study perlreftut and get comfortable with Perl’s dereferencing syntax. It can be quite confusing at first, but if you persevere there will come a point where it will start to “click”, and then you’ll never look back!

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,