•Re: question regarding slices
by merlyn (Sage) on Nov 06, 2003 at 19:14 UTC
|
There is no promise that dot and dot-dot are always the first two entries returned, although it is rare to see them misordered (usually from a disk fsck repair).
The best solution is to leave your check in your loop as you already have. Stop optimizing for things that will break eventually.
| [reply] |
|
|
How to do it with not just 1 slice but 2 slices, and at the same time avoid Merlyn's issue of . and .. not always coming at the start of the list
@l = readdir(PRINT) ;
%h{@l} = (1) x @l ;
delete @h{'.', '..'} ;
for( keys %h ) {
# do work
}
This is probably not what was desired in the first place, since it adds more lines of code, but I thought this would be interesting.
Nuts and Bolts
@l = readdir gets the list of files
%h{@l} = (1) x @l converts the list into a hash, since all elements in a directory are unique
delete @h{'.', '..'} removes the . and .. entries from the hash at whatever position they're hiding in.
for( keys %h) { . and .. free looping | [reply] [d/l] [select] |
|
|
Besides being very likely both longer to type and longer to run, you've also made it less portable, because delete @hash{@list} wasn't added until perl 5.6, if I recall. It might have been 5.5, but it's still a "relatively recent invention" as I often say.
| [reply] |
|
|
| [reply] [d/l] |
Re: question regarding slices
by davido (Cardinal) on Nov 06, 2003 at 18:32 UTC
|
my @array = qw/this that the other/;
local $, = ", ";
print @array[1..$#array], "\n";
__OUTPUT__
that, the, other
An unnamed true list (one that isn't held within a scalar in any way, nor referenced by an array-ref) can't be indexed in such a way as to construct a 0..end-of-list, but you do have a couple of other options.
my $last_item = (this, that, the, other)[-1];
Or the more useful...
my $list = [qw/this that the other/];
local $, = ", ";
print @{$list}[0..$#{$list}];
This last alternative uses an anonymous list referred to by an array-ref scalar.
Dave
"If I had my life to live over again, I'd be a plumber." -- Albert Einstein
| [reply] [d/l] [select] |
|
|
the list has no name..the list is returned by readdir... which you can put into an array like so my @files = readdir(PRINT). However I'm trying to expand my foo and learn to ninja-code it in such a way that doesnt require a variable declaration. Probably shoulda been more clear about that in the original question. Thank you for your information though. I normally use that or just simply the array in a scalar context which will return the size as well.
| [reply] [d/l] |
Re: question regarding slices
by tcf22 (Priest) on Nov 06, 2003 at 18:44 UTC
|
You could use grep, like this
foreach(grep ! /^\.{1,2}$/, readdir(PRINT)){
#do work
}
but it loops through the list twice, which may be a little inefficient, so you could use glob which removes the . and .. automatically.
my $dir = '/path/to/dir';
foreach(glob('$dir/*')){
#do work
}
I prefer using glob().
As for retrieving all but the first 2 elements of the list, it is a little akward, so you could assign them into an array and do this
my @array = readdir(PRINT);
foreach(@array[2..$#array]){
#do work
}
| [reply] [d/l] [select] |
|
|
Don't use grep to filter out these entries. Unless you know what you are doing, you open yourself to security problems (missing a directory you should traverse). And if you do know what you are doing, it looks strange to someone who doesn't, and so they might want to "fix" it and hence break it.
More discussion about this issue can be found at:
And in case the OP isn't aware of them, this might be the right moment to mention File::Find and File::Find::Rule.
| [reply] |
Re: question regarding slices
by QM (Parson) on Nov 06, 2003 at 22:32 UTC
|
Ignoring for the moment Merlyn's comments as to the order of . and .. from readdir...
I feel so slow for not finding this sooner:
foreach ( splice( @{[readdir(PRINT)]}, 2 ) {...}
Because as perldoc -f splice reports:
...If LENGTH is omitted, removes everything from OFFSET onward...
Update: and since splice returns what it removes, this returns all but the first 2 elements, which is a variation on splice I had forgotten.
-QM
--
Quantum Mechanics: The dreams stuff is made of
| [reply] [d/l] [select] |
Re: question regarding slices
by jweed (Chaplain) on Nov 06, 2003 at 18:38 UTC
|
Unfortunately, that can't be done straight from the readdir list beacuse any such try would be clunky and require two calls, like this: foreach(readdir(PRINT)[2...scalar(readdir(PRINT)-1])
Instead, try naming your array and then saying
foreach(@array[2..$#array])
...
This will skip . and .. for you.
UPDATE: Whoops, I was beat. Sorry for reposting old info.
UPDATE 2 : DO NOT USE the method described above. As merlyn so expertly states, . and .. are not always the first files. The glob solution is particuarly pleasing, IMHO. | [reply] [d/l] [select] |
Re: question regarding slices
by TomDLux (Vicar) on Nov 06, 2003 at 23:08 UTC
|
Using glob() is the best solution, since it doesn't include . and .. in the solution set. But, in general, if there are things you want to skip over, I find the NEXT statement with conditional modifier is the clearest solution:
foreach ( readdir PRINT ) {
next if ( ( $_ eq '.' ) or ( $_ eq '..' ) );
# or, alternately ...
next if /^..?$/;
}
The first line is explicitly clear and is fast. Regex cannot be faster than straightfoward string comparison, but in this case the small number of characters and the idiomatic nature makes the code clear to undnerstand.
--
TTTATCGGTCGTTATATAGATGTTTGCA
| [reply] [d/l] |
|
|
Your RE will skip any one- or two-letter entries, not just . and .., since . in an RE means "any character." I think you meant /^\.\.?$/.
| [reply] [d/l] |
Re: question regarding slices
by duct_tape (Hermit) on Nov 06, 2003 at 18:46 UTC
|
I can't think of how to do this, since it is a list instead of an array... it might not be possible. With lists you can use -1 to get the last element, but 2 .. -1 doesn't seem to work.
What about using grep to avoid the check for . and .. within the foreach?
foreach (grep { !/^\.\.?$/ } readdir(PRINT)) {
# stuff
}
I know this isn't what you asked for, but it is another solution. Personally I prefer having the check within the foreach loop like this:
next if (/^\.\.?$/);
Hope that helps.
Brad | [reply] [d/l] [select] |
Re: question regarding slices
by Art_XIV (Hermit) on Nov 10, 2003 at 14:40 UTC
|
I'd check out grep and/or the file test operators before proceeding with filter solution that you propose. Slicing may work, but it's a bit of an off-handed way of doing it.
The file test operators (-e, -s, etc..) should let you select the canidate files that are actually readable or that have readable content.
Doing a grep on your readdir should let you select the files with names/extensions that you want to read. You can even combine the filetests with a grep.
Hanlon's Razor - "Never attribute to malice that which can be adequately explained by stupidity"
| [reply] |