On Wednesday, 19 September 2012 at 03:12:21 UTC, Jonathan M Davis
wrote:
On Wednesday, September 19, 2012 04:50:45 Craig Dillabaugh wrote:
Hello I am trying to read in a set of numbers from a text file.
The file in questions looks something like this:

35  2  0  1
     0    0.49463548699999998  0.88077994719999997    0
     1    0.60672109949999997  0.2254208717    0


After each line I want to check how many numbers were on the line
I just read. My code to read this file looks like:

1 import std.stdio;
2 import std.conv;
3
4 int main( string[] argv ) {
5    real[] numbers_read;
6    size_t line_count=1;
7
8    auto f = std.stdio.File("test.txt", "r");
9    foreach( char[] s; f.byLine() ) {
10     string line = std.string.strip( to!string(s) );
11     auto parts = std.array.splitter( line );
12     writeln("There are ", parts.length, " numbers in line ",
line_count++);
13     foreach(string p; parts) {
14     numbers_read ~= to!real(p);
15      }
16    }
17    f.close();
18    return 0;
19 }

When I try to compile this I get an error:
test.d(12): Error undefined identifier 'length;

However, shouldn't splitter be returning an array (thats what the
docs seem to show)? What is the type of 'parts'? (I tried using
std.traits to figure this out, but that just generated more
syntax errors for me).

The docs do not show that splitter returns an array, because it doesn't. It returns a lazy range type which finds each successive element as you iterate over it. It doesn't have a length property, because it's length isn't known
until you iterate over it. You have three options:

Thanks, a few others have pointed that out to me too.  But as a D
newbie how would I have any clue what splitter returns since the
return type is auto?
The is an example in the docs.

auto a = " a     bcd   ef gh ";
assert(equal(splitter(a), ["", "a", "bcd", "ef", "gh"][]));

I guessed that since the return of splitter was equal to :
["", "a", "bcd", "ef", "gh"][]
it was returning some sort of 2D array!

When a function returns an 'auto' in the Phobos is this generally
indicative of the return value being a range?


1. Use std.array.split, which returns an array (so, it's eager and requires additional memory allocations to create the array, but you'll have its length
without having to iterate over it multiple times).

2. Use std.range.walkLength to get the length of the range. If a range has a length property, then walkLength just returns that, otherwise it iterates over the whole range and counts its elements. So, you won't get extra memory
allocations, but you'll have to iterate over the range twice.

3. Simply count up the number of elements as you iterate over them and _then_
print out the length.

Also, theres no need to convert s to a string like that. If you were saving the string or needed an actual string instead of char[], then that would make sense, but you're just splitting it and then converting it to a number. char[] will work just fine for that. So, something like this would probably be better
I think my problem was that I was trying to call strip on it first
to remove leading/trailing whitespace and I was getting syntax
errors
when I called strip() on the char[]. Just calling split works as
you
say.




import std.conv;
import std.stdio;
import std.string;

void main()
{
    real[] numbers_read;
    size_t line_count = 0;

    auto f = std.stdio.File("test.txt", "r");
    foreach(line; f.byLine())
    {
        line = strip(line);
        auto parts = std.array.splitter(line);
        size_t length = 0;

        foreach(p; parts)
        {
            numbers_read ~= to!real(p);
            ++length;
        }

writeln("There are ", length, " numbers in line ", ++line_count);
    }
}

If you aren't familiar with ranges, then read this

http://ddili.org/ders/d.en/ranges.html

But ranges are used quite heavily in Phobos, so you should be familiar with
them if you intend to use D.

- Jonathan M Davis


Reply via email to