Re: How come a count of a range becomes 0 before a foreach?

2023-04-10 Thread ikelaiah via Digitalmars-d-learn
On Monday, 10 April 2023 at 01:01:59 UTC, Steven Schveighoffer 
wrote:

On 4/9/23 9:16 AM, Ali Çehreli wrote:

On 4/8/23 21:38, ikelaiah wrote:

 > I will modify the code to construct it twice.

Multiple iterations of dirEntries can produce different 
results, which may or may not be what your program will be 
happy with.


Sticking an .array at the end will iterate a single time and 
maintain the list forever because .array returns an array. :)


   auto entries = dirEntries(/* ... */).array;


I'd be cautious of that. I don't know what the underlying code 
uses, it may reuse buffers for e.g. filenames to avoid 
allocation.


If you are confident the directory contents won't change in 
that split-second, then I think iterating twice is fine.


-Steve


Steve,

The Rmd files are not on a network drive, but saved locally.
So, I'm confident, the files won't change in a split-second.

-ikelaiah.



Re: How come a count of a range becomes 0 before a foreach?

2023-04-10 Thread ikelaiah via Digitalmars-d-learn

On Sunday, 9 April 2023 at 13:16:51 UTC, Ali Çehreli wrote:

On 4/8/23 21:38, ikelaiah wrote:

> I will modify the code to construct it twice.

Multiple iterations of dirEntries can produce different 
results, which may or may not be what your program will be 
happy with.


Sticking an .array at the end will iterate a single time and 
maintain the list forever because .array returns an array. :)


  auto entries = dirEntries(/* ... */).array;

Ali



Ali,

I didn't think about returning `dirEntries` as `array`.
Thanks for the Gems (and your online book too).

Regards,
ikelaiah




Re: How come a count of a range becomes 0 before a foreach?

2023-04-08 Thread ikelaiah via Digitalmars-d-learn
On Sunday, 9 April 2023 at 03:39:52 UTC, Steven Schveighoffer 
wrote:

On 4/8/23 9:38 PM, ikelaiah wrote:
// Get files in specified inputPath variable with a specific 
extension
     auto rmdFiles = file.dirEntries(inputPath, 
file.SpanMode.shallow)

     .filter!(f => f.isFile)
     .filter!(f => f.name.endsWith(fileEndsWith));

     // LINE 72 -- WARNING -- If we count the range here, 
later it will become 0 in line 82
     writeln(programName ~ ": number of files found " ~ 
to!string(rmdFiles.walkLength));


dirEntries returns an *input range*, not a *forward range*. 
This means that once it's iterated, it's done.


If you want to iterate it twice, you'll have to construct it 
twice.


-Steve


Steve,

You're absolutely right. I did not read the manual correctly.

It is clearly written 
[here](https://dlang.org/library/std/file/dir_entries.html) that 
`dirEntry` is an `input range`.


I will modify the code to construct it twice.
Many thanks!

-ikelaiah


How come a count of a range becomes 0 before a foreach?

2023-04-08 Thread ikelaiah via Digitalmars-d-learn

Hi,

I've written a file that converts Rmd (R Markdown file), to a 
MarkDown file.


All works well if and only if line 73 is commented out.

I marked line 72 in the code below.

If line 73 is not commented out, `foreach` does not execute as 
the `rmdFiles.walklength` in line 82 becomes `0`.


How does `rmdFiles.walkLength` becomes `0` before the `foreach`? 
I'm a but confused.


Can someone clarify? Thank you.


```d
module rmd2md;

import std.algorithm;
import std.stdio;
import file = std.file;
import std.conv;
import std.regex;
import std.getopt;
import std.path;
import std.datetime;
import std.parallelism;
import std.range;

void main(string[] args)
{
// Set variables for the main program
string programName = "Rmd2md";

// Setup Regex for capturing Rmd code snippet header
Regex!char re = regex(r"`{3}\{r[a-zA-Z0-9= ]*\}", "g");

// Set default values for the arguments
string inputPath = file.getcwd();
string fileEndsWith = ".Rmd";
string outputPath = file.getcwd();

// Set GetOpt variables
auto helpInformation = getopt(
args,
"path|p", "Path of Rmd files. Default: current working 
directory.", ,
"fext|e", "Extension of Rmd files. Default: `.Rmd`", 
,
"fout|o", "Output folder to save the MD files. Default: 
current working directory.", 

);

if (helpInformation.helpWanted)
{
defaultGetoptPrinter("Rmd to Markdown (md) file 
converter.",

helpInformation.options);
return;
}

// is the path valid?
if (!std.path.isValidPath(inputPath))
{
writeln(programName ~ ": invalid input path");
return;
}

// is output path valid?
if (!std.path.isValidPath(outputPath))
{
writeln(programName ~ ": invalid output path");
return;
}

// is file extension valid?
if (!startsWith(fileEndsWith, "."))
{
writeln(programName ~ ": invalid extension given");
return;
}

writeln(programName ~ ": input directory is " ~ inputPath);
writeln(programName ~ ": output directory is " ~ outputPath);
writeln(programName ~ ": ...");

// Get files in specified inputPath variable with a specific 
extension
auto rmdFiles = file.dirEntries(inputPath, 
file.SpanMode.shallow)

.filter!(f => f.isFile)
.filter!(f => f.name.endsWith(fileEndsWith));

// LINE 72 -- WARNING -- If we count the range here, later it 
will become 0 in line 82
writeln(programName ~ ": number of files found " ~ 
to!string(rmdFiles.walkLength));


// Get start time
auto stattime = Clock.currTime();

// Process each Rmd file
int fileWrittenCount = 0;

// LINE 81 -- WARNING -- if line 73 is not commented out, the 
walkLength returns 0
writeln(programName ~ ": number of files found " ~ 
to!string(rmdFiles.walkLength));


foreach (file.DirEntry item; parallel(rmdFiles))
{
writeln(programName ~ ": processing " ~ item.name);

try
{
// Read content as string
string content = file.readText(item.name);
// Replace ```{r} or ```{r option1=value} with ```R
string modified = replaceAll(content, re, "```R");
// Set the Markdown output file
string outputFile = replaceAll(baseName(item.name), 
regex(r".Rmd"), ".md");
// Build an output path, using output path and 
baseName(item.name)
string outputFilenamePath = buildPath(outputPath, 
outputFile);

// Save output Markdown file
file.write(outputFilenamePath, modified);
writeln(programName ~ ": written " ~ 
outputFilenamePath);
// Increase counter to indicate number of files 
processed

fileWrittenCount++;
}
catch (file.FileException e)
{
writeln(programName ~ ": " ~ e.msg);
}
}

writeln(programName ~ ": ...");

// Gett end clock
auto endttime = Clock.currTime();
auto duration = endttime - stattime;
writeln("Duration: ", duration);

// Console output a summary
writeln(programName ~ ": written " ~ 
to!string(fileWrittenCount) ~ " files");

}
```


For testing, you can create a text file, save as `.Rmd` in the 
same folder as the D file. Run the script as:


```bash
rdmd rmd2md.d
```

It will find the `.Rmd` file in current path and save it in the 
current path.


Re: My new programming book ...

2022-11-06 Thread ikelaiah via Digitalmars-d-learn

On Monday, 7 November 2022 at 00:55:33 UTC, zjh wrote:


Is there a second edition? After all, it has been many years.


Hi zjh,

I'm aware of the publication date. However, I find the content 
still highly relevant to many day-to-day tasks (my use case).


No doubt, there will be new features in the std library.
For further/additional tips and tricks, I'd gladly ask in the D 
discord channel or this forum.


-Ikel




My new programming book ...

2022-11-06 Thread ikelaiah via Digitalmars-d-learn

Hi,

I got a new programming book yesterday, authored by Adam D. Rupee.

![new-book](https://www.linkpicture.com/q/20221106_142031_1.jpg).

I'm still in **Chapter 1**, on the matter of `Immutable` 
variables.
Can't wait to read **Chapter 7** on **Corectness and 
Documentation**.


So far, I really like the book.

- Alexandrei's foreword on the importance of drawing experience 
from and for others.
- The book convention (code, info, warning, new terms, etc) is 
easy to follow.

- The explanation is also easy to digest.


A bit of context of myself: I used to do C++, Java and C#.
Currently work with: Python, R, PHP, SQL, common web-stack (html, 
css, js+libs).


I'm  hoping to integrate more D into my data transformation and 
data reporting workflow.


@Adam D. Rupee, thanks for this book.

Regards,
Ikel








Re: Main foreach loop fails when another foreach is added

2022-08-07 Thread ikelaiah via Digitalmars-d-learn
On Monday, 8 August 2022 at 02:45:54 UTC, Steven Schveighoffer 
wrote:


And now, you tried to read it again! Which means you are trying 
to read more data from an empty stream.


You need to either a) reopen the file, or b) do both in the 
same loop.



-Steve


Steve! You are Legend!
**Thank you**.
It is obvious now the second `foreach` is reading from an empty 
stream!


Regards,
ikel


Main foreach loop fails when another foreach is added

2022-08-07 Thread ikelaiah via Digitalmars-d-learn

Hi,

I'm writing a program that reads a text file and launch my work 
URLs in it.

It worked fine, and very happy.

Then I added another `foreach` loop to count total number of 
lines.

After this, the main `foreach` won't work.

Does anyone know as to why this happens?
I might have missed something very obvious.

Thank you.

Regards,
ikel


```d
module openurls;

import std.stdio : writeln, File, KeepTerminator;
import std.file;
import std.range;
import std.ascii;
import std.getopt : getopt, GetoptResult, defaultGetoptPrinter;
import std.process : browse;
import core.thread.osthread;
import core.time;


void main(string[] args)
{
string input_filename = "";

// Get command line option
GetoptResult user_args = getopt(args,
"input|i", "A list of URLs separated by new lines.", 
_filename);


// Does user need help?
if (user_args.helpWanted)
{
defaultGetoptPrinter("Command line options for Open 
URLs.",

user_args.options);
}

// Is input file specified?
if (input_filename.length == 0)
{
writeln("Open URL: No file specified.\n");
defaultGetoptPrinter("Command line option for Open URLs.",
user_args.options);
return;
}

// Does the file exist?
if (!input_filename.exists)
{
writeln("Open URL: input file --" ~ input_filename ~ "-- 
does not exist.\n");

return;
}
else
{
writeln("Open URL: reading --" ~ input_filename ~ "--");
}

// Open input file for reading
size_t line_count = 0;
File input_file = File(input_filename);
auto file_range = input_file.byLine(KeepTerminator.no, 
std.ascii.newline);


// if this foreach not commented out
// the last foreach won't run.
foreach (char[] line; file_range)
{
line_count += 1;
}

// the MAIN foreach loop
// -- won't run if above foreach is enabled
foreach (char[] line; file_range)
{
if (!line.empty)
{
writeln("Open URL: " ~ line);
Thread.sleep(dur!("seconds")(2));
browse(line);
}
}

writeln("Open URL: completed");

writeln("Closing " ~ input_filename);
input_file.close();
}

```


Re: Combining JSON arrays into a single JSON array -- better way than this?

2022-08-01 Thread ikelaiah via Digitalmars-d-learn

On Monday, 1 August 2022 at 17:02:10 UTC, Salih Dincer wrote:



When printing the steps `import std.stdio : writeln;` use it. 
Thus, it does not conflict with `std.file`.


SDB@79


Will do and thank you for this.



Re: Combining JSON arrays into a single JSON array -- better way than this?

2022-08-01 Thread ikelaiah via Digitalmars-d-learn

On Monday, 1 August 2022 at 16:11:52 UTC, frame wrote:

... because loading all in memory while not necessary is wasted 
memory if you have large files to process.


Noted with thanks. Actually, some JSON input files are pretty 
large (>1Mb).


I would just process each file and write it to the file 
directly but it always depends on the intended purpose.


Noted as well. Thank you, this will come handy in the future.

-ikel




Re: Combining JSON arrays into a single JSON array -- better way than this?

2022-08-01 Thread ikelaiah via Digitalmars-d-learn

On Monday, 1 August 2022 at 05:52:36 UTC, frame wrote:



If the JSON files are already parsed, why you stringify and 
reparse it?




Because of ...

1. mental block and
2. I didn't know `jsonResult.array = [];`

Many thanks for pointing this out. I tried the following, and 
didn't work, and hence my earlier convoluted approach:


- `JSONValue[] jsonResult;`
- `JSONValue jsonResult = [];`



A plain array should be also mergeable via `jsonResult.array ~= 
j.array` (if `j` really is an array, you need to check the type 
first)




Based in your suggestion, the snippet is now more brief.

```d
module combinejsonv3;

import std.file;
import std.stdio;
import std.json;
import std.array;
import std.algorithm.searching;

void main()
{
// merged JSON to be stored here
JSONValue jsonResult;
jsonResult.array = [];

foreach (string filename; dirEntries(".", "*.json", 
SpanMode.shallow))

{
// if filename contains 'output' in it, ignore
if(canFind(filename, "output")) {
std.stdio.writeln("ignoring: " ~ filename);
continue;
}

// read JSON file as string
string content = std.file.readText(filename);

// parse as JSON
JSONValue j = parseJSON(content);

// if JSONType is array, merge
if(j.type == JSONType.array) {
// show status to console
std.stdio.writeln("processing JSON array from: " 
~ filename);

jsonResult.array ~= j.array;
}
}

// write to file
std.file.write("output-combined.json", 
jsonResult.toPrettyString);

}
```

Thank you!

-ikel


Re: Combining JSON arrays into a single JSON array -- better way than this?

2022-08-01 Thread ikelaiah via Digitalmars-d-learn

On Monday, 1 August 2022 at 07:35:34 UTC, Christian Köstlin wrote:

An arguably shorter solution (that drops some of your logging) 
could be:


```d
import std;

void main() {
dirEntries(".", "*.json", SpanMode.shallow)
.filter!(f => !f.name.canFind("output"))
.map!(readText)
.map!(parseJSON)
.fold!((result, json) { result ~= json.array; return 
result; })

.toPrettyString
.reverseArgs!(std.file.write)("output-combined.json");
}
```
not sure if you are looking for this style though.


kind regards,
Christian



Hi Christian,

So we can do that in D?!
Thanks for sharing this amazing approach.

-ikelaiah



Combining JSON arrays into a single JSON array -- better way than this?

2022-07-31 Thread ikelaiah via Digitalmars-d-learn

Hi,

I've written a cli tool to merge JSON files (containing JSON 
array) in the current folder as a single JSON file.


My algorithm:

1. Create a string to store the output JSON array as a string,
2. read each file
3. read each object in JSON array from input file
4. append the string representation of each JSON object in a 
string

5. Parse the result string as JSON
6. Save string representation of point 6 above.

**Question**

While this works, is there a more concise way than this?
Thank you for your time.


```d
module combinejsonv2;

import std.file;
import std.stdio;
import std.json;
import std.array;
import std.algorithm.searching;

void main()
{
// can't I use this for JSON array?
JSONValue jj;

// create a string opening [ for JSON array
string stringResult = "[";

foreach (string filename; dirEntries(".", "*.json", 
SpanMode.shallow))

{
// if filename contains 'output' in it, ignore
if(canFind(filename, "output")) {
std.stdio.writeln("ignoring: " ~ filename);
continue;
}

// show status to console
std.stdio.writeln("processing: " ~ filename);

// read JSON file as string
string content = std.file.readText(filename);
// parse as JSON
JSONValue j = parseJSON(content);

foreach (JSONValue jsonObject; j.array) {
// Combine objects from files into a single list of 
JSON object

// std.stdio.writeln(jsonObject.toPrettyString);
stringResult ~= jsonObject.toString;
stringResult ~= ",";
}
}

// create closing ] for the JSON array
stringResult ~= "]";

// parse the string as a JSON object
JSONValue jsonResult = parseJSON(stringResult);

// write to file
std.file.write("output-combined.json", 
jsonResult.toPrettyString);

}

```