Re: Working with a unknown number of arrays
by davorg (Chancellor) on Feb 05, 2007 at 16:42 UTC
|
Whatever you do, please don't consider using a variable as a variable name.
Instead you should look at complex data structures like arrays of arrays. See perlreftut, perllol and perldsc for details.
Code review notes follow:
opendir (*LOWEST, "$input_directory_lowest")
Please take another look at the documentation for opendir. You are still getting it wrong. You pass it the name of a directory handle (LOWEST) not a typeglob (*LOWEST). And there is no need to quote the variable $input_directory_lowest.
if ($do_I_pick_up_request == 'Y')
And how many times have people tried to explain the difference between string and numeric comparison operators to you?
| [reply] [d/l] [select] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: Working with a unkown number of arrays
by jdporter (Paladin) on Feb 05, 2007 at 17:14 UTC
|
I think you're definitely on the track, to want to generalize the code to any number of directories. The first thing to do is try to eliminate variables — or rather, variable names — which perpetuate the "one chunk of code per directory" mentality.
Below is how you might reduce it to a loop.
sub Prioritise_requests
{
my( $input_directory, $node ) = @_;
for my $dir_num ( '1', '2', '3' )
{
my $input_dir = $input_directory.$dir_num;
opendir DIR, $input_dir or die "Error opening directory $input_dir
+ - $!";
my @files =
sort { -M $a <=> -M $b }
map "$input_dir/$_",
grep /^Flat_file.*\.txt$/,
readdir DIR;
closedir DIR;
foreach ( @files )
{
if ( Is_the_file_mine($node, $_) and Do_I_run_the_request_now($_
+) )
{
move $_, $input_directory or warn "Error moving $_ to $input_d
+irectory - $!";
return;
}
}
}
}
I've also made one critical bug fix in the code above:
You have to add the directory name to the file name before you get any of the file's information, e.g. -M.
Also, I made a change as to the assumed return values of the two hypothetical subroutines Is_the_file_mine and Do_I_run_the_request_now.
You were assuming they'd return characters. But really, they return boolean (true/false) conditions. May as well just code for that directly.
A word spoken in Mind will reach its own level, in the objective world, by its own weight
| [reply] [d/l] [select] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: Working with a unkown number of arrays
by wojtyk (Friar) on Feb 05, 2007 at 17:02 UTC
|
You've gone about this problem in a somewhat ugly manner (it appears as if you cut and pasted the same code 3 times). A more elegant solution would store everything in a hash with the priority level included. So each priority value would be a key and file (or directory) would be a value (or vice versa). Then you could just sort by hash key/value.
Pseudo-code:
sub Prioritise_requests {
my ($input_directory, $node) = @_;
my %files;
$files{1} = $input_directory."1";
$files{2} = $input_directory."2";
$files{3} = $input_directory,"3";
# this is looping on the directories in a prioritized manner
foreach (sort keys %files) {
open(*DATA,$_) or die;
# this is looping through each file you want in each directory
foreach (sort grep(/^Flat_file.*\.txt$/,readdir(DATA))) {
# do your stuff for each file
}
close(DATA);
}
}
| [reply] [d/l] |
|
|
Hi, I understand that what you wrote is marked as "pseudocode", but I noticed a couple of strange things:
$files{3} = $input_directory,"3";
Maybe you meant to put a dot "." instead of a comma ","?
Another thing that I don't understand from this fragment is if %files holds filenames or directory names. The use of open() and close() seems to point to "filenames", but in this case the readdir(DATA) should be simply <DATA>.
Regarding the open(), at the price of backward compatibility with 5.6, I use lexical filehandles instead of barewords: open my $data, ...
Moreover, I usually stick to the three argument version of open(), not because this is requested by this particular application (I actually don't know), but more for sake of a mental habit (yes, I'm mental :) : open my $data, '<', $files{$_} ...
I find it better not only because it avoids nasty problems when the filename comes from the "untrusted external" (which could lead to embarassing security holes), but also because it visually marks that this open is for read instead of write.
Last, even if the plain die does the work (especially in pseudocode!), it could be helpful to provide a more sensible feedback message, either directly: open my $data, '<', $files{$_} or die "open('$files{$_}'): $!";
or withuse Fatal qw( open );
in the script's preamble.
Forgive me for jumping on your shoulders this way, but the OP seems to have some bias towards blind cut-and-paste, you know, so it could be useful for her|him to think about these issues ;)
Flavio
perl -ple'$_=reverse' <<<ti.xittelop@oivalf
Don't fool yourself.
| [reply] [d/l] [select] |
|
|
>c:\progs\perl560\bin\perl script.pl
open(my $data, '<', $0) or die;
print while <$data>;
Lexical handles were introduced in 5.6, so you are sacrificing backwards compatibility wih 5.5 (5.005).
What was introduced in 5.8 is file handles to variables (open(my $fh, '<', \$buf)).
| [reply] [d/l] [select] |
|
|
Heh, no worries.
I wasn't exactly trying to meet stellar code standards.
It was the best I could spit out in about 30-40 seconds ;)
| [reply] |
|
|
That open(DATA) line should be:
open(*DATA,$files{$_}) or die;
You get the point though. | [reply] [d/l] |
|
|
open(DATA, $files{$_}) or die $!;
Removed unnecessary typeglob symbol and added error message.
| [reply] [d/l] |
|
|
Re: Working with a unkown number of arrays
by jdporter (Paladin) on Feb 05, 2007 at 17:00 UTC
|
Question: In the code above, you only do anything (processing files in any folder) if there is something in the high-priority folder.
Specifically, you have:
if (@sorted_highest_priority) {
foreach (@sorted_highest_priority){
...
}
if (@sorted_middle_priority) {
foreach (@sorted_middle_priority){
...
}
}
if (@sorted_lowest_priority) {
foreach (@sorted_lowest_priority){
...
}
}
}
That's a mistake, right?
A word spoken in Mind will reach its own level, in the objective world, by its own weight
| [reply] [d/l] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: Working with a unkown number of arrays
by Moron (Curate) on Feb 05, 2007 at 17:28 UTC
|
Files of lower priority are unprocessed, so the finding can be cut short when files are found in a higher folder.e.g. my @folders = glob 'input_directory*'; # get/sort all qualifying folde
+rs
my @requests;
for (my ($found, %filedate); $found = pop @folders or exit();) {
@requests = sort {
{ ( $filedate{ $a } ||= -M $a )
<=> ( $filedate{ $b } ||= -M $b )
} glob "$found/" . 'Flat_file.*.txt'
and last; # reiterate iff none found
}
If the loop completes having found @requests, they will have been selected from the highest non-empty qualifying directory and be sorted by creation/modification date. (updated)
| [reply] [d/l] |
Re: Working with a unkown number of arrays
by GrandFather (Saint) on Feb 05, 2007 at 20:54 UTC
|
use warnings;
use strict;
my $inputdir;
my %files = Prioritise_requests ($inputdir);
for my $fileList (sort keys %files) {
print "$files{$file}->[0]\n"; # Lowest priority file
print "$files{$file}->[-1]\n"; # Top priority file
}
sub Prioritise_requests {
my ($input_directory, $node) = @_;
my %files;
my $index = 1;
while (1) {
last if ! opendir SCAN, "$input_directory$index";
for my $filePath (grep (/^Flat_file.*\.txt$/, readdir (SCAN)))
+ {
my ($file) = $filePath =~ m![^\\/]*$!;
push @{$files{$file}}, $_;
++$index;
}
closedir SCAN;
}
return %files;
}
Note that this is untested and doesn't include all the "non-issue" work of your sample code.
Updated to avoid "perpetual" loop
DWIM is Perl's answer to Gödel
| [reply] [d/l] |
A reply falls below the community's threshold of quality. You may see it by logging in. |