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