splitting numbers from a test file
Jonathan M Davis
jmdavisProg at gmx.com
Tue Sep 18 20:13:06 PDT 2012
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:
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
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
More information about the Digitalmars-d-learn
mailing list