www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Converting from DirIterator to string[] without a loop

reply Dave Chapman <donte5379 comcast.net> writes:
I would like to do something like the code shown below but I 
can't figure out how to do
it without loops inside the if statement.
When I use auto and print out the type of b it is  something like
args.main.FilterResult!(__lambda2, DirIterator).FilterResult and 
for the "if" version of
b and args.main.FilterResult!(__lambda3, 
DirIterator).FilterResult for the "else" version
so they are really different types. I have tried making b an 
array of DirEntry and an
array of strings but that doesn't compile. Both expressions for b 
compile and run.

I can put a foreach loop inside the if statement and convert b to 
an array of strings but that
seems clumsy and not idiomatic D. Is there a way to do this 
without the conversion loop
inside both branches of the if - else stament? Is there a way to 
use to!string or cast?

// Is it possible to make this work?
theResultType b;

if (some_contition) {
   b = dirEntries("directory", SpanMode.shallow).filter!(f => 
(f.name == "file_name.txt") );
} else {
   b = dirEntries("directory", SpanMode.shallow).filter!(f => 
(f.name.endsWith(".d") )'
}

foreach(file; b) {
    do some stuff
}


// This works but seems clumsy and not idiomatic D
string[] c = "";

if (some_contition) {
   auto b = dirEntries("directory", SpanMode.shallow).filter!(f => 
(f.name == "file_name.txt") );
   foreach (file; b) {
     c = c ~ file;
   }
} else {
   auto b = dirEntries("directory", SpanMode.shallow).filter!(f => 
(f.name.endsWith(".d") )'
     foreach (file; a) {
       c = c ~ file;
     }
}

foreach(file; c) {
    do some stuff
}
Jan 13 2017
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/13/2017 04:29 PM, Dave Chapman wrote:

 When I use auto and print out the type of b it is  something like
 args.main.FilterResult!(__lambda2, DirIterator).FilterResult and for the
 "if" version of
 b and args.main.FilterResult!(__lambda3, DirIterator).FilterResult for
 the "else" version
 so they are really different types.
The solution for that case is to use std.range.choose: auto b = choose(some_condition, all.filter!(f => baseName(f.name) == "file_name.txt"), all.filter!(f => (f.name.endsWith(".d") ))); but I get the following error with DMD64 D Compiler v2.072.1: Error: no property '__postblit' for type 'FilterResult!(__lambda2, DirIterator)', did you mean '__xpostblit'? So, I put .array after both expressions below. The idiomatic way for what you're looking for is std.array.array (which is also exposed through std.range): import std.stdio; import std.file; import std.algorithm; import std.range; import std.path; void main(string[] args) { bool some_condition = (args.length > 1) && (args[1] == "foo"); auto all = dirEntries("directory", SpanMode.shallow); auto b = choose(some_condition, all.filter!(f => baseName(f.name) == "file_name.txt").array, all.filter!(f => (f.name.endsWith(".d") )).array); writeln(b); } However, in most cases keeping 'b' as a lazy algorithm is sufficient. Unless you really need an array e.g. for sorting, you can use std.algorithm.each (or map, etc.). (Not applicable in this case because of the error I mentioned above.) Ali
Jan 13 2017
parent Dave Chapman <donte5379 comcast.net> writes:
On Saturday, 14 January 2017 at 01:02:38 UTC, Ali Çehreli wrote:
 On 01/13/2017 04:29 PM, Dave Chapman wrote:

 When I use auto and print out the type of b it is  something
like
 args.main.FilterResult!(__lambda2, DirIterator).FilterResult
and for the
 "if" version of
 b and args.main.FilterResult!(__lambda3,
DirIterator).FilterResult for
 the "else" version
 so they are really different types.
The solution for that case is to use std.range.choose: auto b = choose(some_condition, all.filter!(f => baseName(f.name) == "file_name.txt"), all.filter!(f => (f.name.endsWith(".d") ))); but I get the following error with DMD64 D Compiler v2.072.1: Error: no property '__postblit' for type 'FilterResult!(__lambda2, DirIterator)', did you mean '__xpostblit'? So, I put .array after both expressions below. The idiomatic way for what you're looking for is std.array.array (which is also exposed through std.range): import std.stdio; import std.file; import std.algorithm; import std.range; import std.path; void main(string[] args) { bool some_condition = (args.length > 1) && (args[1] == "foo"); auto all = dirEntries("directory", SpanMode.shallow); auto b = choose(some_condition, all.filter!(f => baseName(f.name) == "file_name.txt").array, all.filter!(f => (f.name.endsWith(".d") )).array); writeln(b); } However, in most cases keeping 'b' as a lazy algorithm is sufficient. Unless you really need an array e.g. for sorting, you can use std.algorithm.each (or map, etc.). (Not applicable in this case because of the error I mentioned above.) Ali
Thank you very much. I had a little trouble getting it working. It was acting as if both halves of the "choose" expression were always getting executed and the first half was making the contents of "all" empty and so the array b was always empty if I used the second half of the choose statement. I made a second copy of "all" and used it in the second half of the choose statement and then it worked. Like this: auto all = dirEntries("directory", SpanMode.shallow); auto all_2 = dirEntries("directory", SpanMode.shallow); auto b = choose(some_condition, all.filter!(f => (baseName(f.name) == requested_file)).array, all_2.filter!(f => (f.name.endsWith(".html") )).array); Note that I am really using requested_file instead of "file_name.txt" and ".html" instead of ".d" which is different than what I told you before just in case that matters. I am using Mac OS X 10.11.5 and dmd version 2.072.2 Thanks again for the help, Dave
Jan 14 2017