Thread overview
input range from stdin
Sep 17, 2014
krzaq
Sep 17, 2014
Marc Schütz
Sep 17, 2014
krzaq
Sep 17, 2014
Ali Çehreli
Sep 18, 2014
krzaq
Sep 18, 2014
Marc Schütz
Sep 18, 2014
krzaq
Sep 18, 2014
Marc Schütz
Sep 18, 2014
Ali Çehreli
Sep 18, 2014
Ali Çehreli
September 17, 2014
I'd like to have something similar to C++'s std::istream_iterator<int>(std::cin)

Is it possible? I'm relatively indifferent to efficiency of the solution.
September 17, 2014
On Wednesday, 17 September 2014 at 12:44:00 UTC, krzaq wrote:
> I'd like to have something similar to C++'s std::istream_iterator<int>(std::cin)
>
> Is it possible? I'm relatively indifferent to efficiency of the solution.

import std.stdio;
import std.algorithm;
import std.conv;
writeln(stdin.byLine.map!(to!int));
September 17, 2014
On Wednesday, 17 September 2014 at 14:37:21 UTC, Marc Schütz wrote:
> On Wednesday, 17 September 2014 at 12:44:00 UTC, krzaq wrote:
>> I'd like to have something similar to C++'s std::istream_iterator<int>(std::cin)
>>
>> Is it possible? I'm relatively indifferent to efficiency of the solution.
>
> import std.stdio;
> import std.algorithm;
> import std.conv;
> writeln(stdin.byLine.map!(to!int));

What happens if I later have some strings that I want to read from the same line?

How can I use the resultant range with std.fill?

My idea doesn't seem to work: http://dpaste.dzfl.pl/130e14c927f3
September 17, 2014
On 09/17/2014 08:30 AM, krzaq wrote:
> On Wednesday, 17 September 2014 at 14:37:21 UTC, Marc Schütz wrote:
>> On Wednesday, 17 September 2014 at 12:44:00 UTC, krzaq wrote:
>>> I'd like to have something similar to C++'s
>>> std::istream_iterator<int>(std::cin)
>>>
>>> Is it possible? I'm relatively indifferent to efficiency of the
>>> solution.
>>
>> import std.stdio;
>> import std.algorithm;
>> import std.conv;
>> writeln(stdin.byLine.map!(to!int));
>
> What happens if I later have some strings that I want to read from the
> same line?
>
> How can I use the resultant range with std.fill?
>
> My idea doesn't seem to work: http://dpaste.dzfl.pl/130e14c927f3

The following worked:

import std.stdio;
import std.format;
import std.exception;
import std.string;
import std.algorithm;

struct Data
{
    int i;
    string s;
}

Data toData(char[] line)
{
    int i;
    string s;
    auto slice = line;

    const items = formattedRead(line, " %s %s", &i, &s);
    enforce (items == 2, format("Incomplete line: %s", slice));

    return Data(i, s);
}

void main()
{
    auto data = stdin.byLine.map!toData;
    writeln(data);
}

I could not get it work with fill because fill requires specific types of ranges, which neither the destination nor the source were. For example, I wanted to use std.array.Appender but fill wants an InputRange. Also, the source is not a ForwardRange because it is consuming from stdin.

However, it is easy to make an array with std.array.array:

    import std.array;
    writeln(data.array);

Ali

September 18, 2014
On Wednesday, 17 September 2014 at 18:05:36 UTC, Ali Çehreli wrote:
> On 09/17/2014 08:30 AM, krzaq wrote:
>> On Wednesday, 17 September 2014 at 14:37:21 UTC, Marc Schütz wrote:
>>> On Wednesday, 17 September 2014 at 12:44:00 UTC, krzaq wrote:
>>>> I'd like to have something similar to C++'s
>>>> std::istream_iterator<int>(std::cin)
>>>>
>>>> Is it possible? I'm relatively indifferent to efficiency of the
>>>> solution.
>>>
>>> import std.stdio;
>>> import std.algorithm;
>>> import std.conv;
>>> writeln(stdin.byLine.map!(to!int));
>>
>> What happens if I later have some strings that I want to read from the
>> same line?
>>
>> How can I use the resultant range with std.fill?
>>
>> My idea doesn't seem to work: http://dpaste.dzfl.pl/130e14c927f3
>
> The following worked:
>
> import std.stdio;
> import std.format;
> import std.exception;
> import std.string;
> import std.algorithm;
>
> struct Data
> {
>     int i;
>     string s;
> }
>
> Data toData(char[] line)
> {
>     int i;
>     string s;
>     auto slice = line;
>
>     const items = formattedRead(line, " %s %s", &i, &s);
>     enforce (items == 2, format("Incomplete line: %s", slice));
>
>     return Data(i, s);
> }
>
> void main()
> {
>     auto data = stdin.byLine.map!toData;
>     writeln(data);
> }
>
> I could not get it work with fill because fill requires specific types of ranges, which neither the destination nor the source were. For example, I wanted to use std.array.Appender but fill wants an InputRange. Also, the source is not a ForwardRange because it is consuming from stdin.
>
> However, it is easy to make an array with std.array.array:
>
>     import std.array;
>     writeln(data.array);
>
> Ali

Thank you for your reply.

That's not what I wanted. Maybe I should explain instead of expecting you to divine my intentions, though :) I am trying to rewrite the following program in D--making it more elegant: http://melpon.org/wandbox/permlink/ff42FoyKgqJK60sm

As you can see, I can have one input line consisting of n words and then n integers and I can read from it easily. My question whether stdin.byLine allows me to do this remains unanswered (or I failed to understand the answer), although I am not hopeful.

As to std.fill: I find myself surprised. Any idea why the input range is considered incorrect? In any case, should integers[0..$].fill(...) not make it correct, at least in regards to the first argument? Docs have an example with int[]

I expected my D code to look more or less like the following:

words.fill(stdin.by!string);
integers.fill(stdin.by!int);
zip(integers,words).map!(p => p[1][p[0]]).join.writeln;

September 18, 2014
On Thursday, 18 September 2014 at 09:21:17 UTC, krzaq wrote:
> That's not what I wanted. Maybe I should explain instead of expecting you to divine my intentions, though :) I am trying to rewrite the following program in D--making it more elegant: http://melpon.org/wandbox/permlink/ff42FoyKgqJK60sm
>
> As you can see, I can have one input line consisting of n words and then n integers and I can read from it easily. My question whether stdin.byLine allows me to do this remains unanswered (or I failed to understand the answer), although I am not hopeful.

You should be able to use `std.algorithm.take` to read exactly 5 integers. However, in order to read up to the first empty line, for example, the input would have to be a forward range (= "rewindable"), which stdin.byLine of course is not. Maybe you could constructor a wrapper range that caches input lines as necessary.
September 18, 2014
On Thursday, 18 September 2014 at 11:13:36 UTC, Marc Schütz wrote:
> On Thursday, 18 September 2014 at 09:21:17 UTC, krzaq wrote:
>> That's not what I wanted. Maybe I should explain instead of expecting you to divine my intentions, though :) I am trying to rewrite the following program in D--making it more elegant: http://melpon.org/wandbox/permlink/ff42FoyKgqJK60sm
>>
>> As you can see, I can have one input line consisting of n words and then n integers and I can read from it easily. My question whether stdin.byLine allows me to do this remains unanswered (or I failed to understand the answer), although I am not hopeful.
>
> You should be able to use `std.algorithm.take` to read exactly 5 integers. However, in order to read up to the first empty line, for example, the input would have to be a forward range (= "rewindable"), which stdin.byLine of course is not. Maybe you could constructor a wrapper range that caches input lines as necessary.

Okay, I think I'll simply skip this for now.

I hoped that there would be a way of reading stdin composable with std.algorithms, as is the case in C++.

I guess this works for now http://dpaste.dzfl.pl/6801615160e3

I have a follow-up question: why does zip not accept an array?
September 18, 2014
On Thursday, 18 September 2014 at 13:10:06 UTC, krzaq wrote:
> I guess this works for now http://dpaste.dzfl.pl/6801615160e3
>
> I have a follow-up question: why does zip not accept an array?

Because (fixed-sized) arrays don't have a range interface (empty, front & popFront()), in particular, popFront cannot be used on them. That's why a slice is needed.

Btw, you can just write `array_name[]` without `0 .. $` to get a slice of the entire array.
September 18, 2014
On 09/18/2014 02:21 AM, krzaq wrote:

> That's not what I wanted. Maybe I should explain instead of expecting
> you to divine my intentions, though :)

And quietly ignored some of the things you were doing. :)

For example, I did not think it was necessary to fill an existing array when the range object can produce the objects one by one lazily. If an actual array is needed, it is as simple as calling .array on the range.

An if the destination already exists, the array-wise operations can fill it anyway. So, actually fill is not needed in the original case:

    import std.array;
    import std.range;

    Data[5] existingArray;
    existingArray = data.takeExactly(5).array;

> I am trying to rewrite the
> following program in D--making it more elegant:
> http://melpon.org/wandbox/permlink/ff42FoyKgqJK60sm

Here is my attempt:

import std.stdio;
import std.algorithm;
import std.range;
import std.conv;

auto secretWord(R)(R line)
{
    auto tokens = line.splitter;

    auto words = tokens
                 .takeExactly(5);

    // Question: Why do I need this?
    tokens.popFrontN(words.length);

    auto integers = tokens
                    .takeExactly(words.length)
                    .map!(to!size_t);

    return zip(words, integers).map!(t => t[0][t[1]]);
}

unittest
{
    assert(secretWord("cheap energy can cause problems 4 2 1 0 5")
           .equal("peace"));
}

void main()
{
    writeln(stdin.byLine.map!secretWord);
}

> As you can see, I can have one input line consisting of n words and then
> n integers and I can read from it easily. My question whether
> stdin.byLine allows me to do this remains unanswered (or I failed to
> understand the answer), although I am not hopeful.

byLine's purpose is to present the input line by line. Parsing the line should be the responsibility of something else. However, you are right that we don't have a generic formetted range reader yet.

There has been a number of talks about it but nobody has completed it yet.

> I expected my D code to look more or less like the following:
>
> words.fill(stdin.by!string);
> integers.fill(stdin.by!int);
> zip(integers,words).map!(p => p[1][p[0]]).join.writeln;

I wrote my code without looking yours. :)

Ali

September 18, 2014
On 09/18/2014 11:22 AM, Ali Çehreli wrote:

> And quietly ignored

And *I* quietly ignored

Ali