best way to convert string array of floats to a float array

Jonathan M Davis jmdavisProg at gmx.com
Tue Jul 24 21:33:20 PDT 2012


On Wednesday, July 25, 2012 06:18:13 Stephen Jones wrote:
> Thanks Jonathan. Very cool language this:
> 
> float[] dat;
> dat~=array(map!(to!(float))(split(chompPrefix(s, "lno:"))));
> 
> The data is read from a string that contains floats, parsed by
> the split into an array, converted into an array of auto via the
> mapping with the to!float function, and then cast into the float
> array dat.
> 
> Longhand that data would be read into the program as a string,
> converted into an array of strings then converted into an array
> of floats and the initial string and the array of strings would
> both accumulate on the GC waiting list. Does the code above weed
> out some of the redundant data thereby reducing calls upon the GC?

I'm not quite sure what you mean. Are you asking whether it tries to avoid 
unnecessary copies? It's pretty straightforward in what it does, but there 
_is_ some copying going on here.

chompPrefix slices s, so there's no copying.

split _does_ copy, since it returns a new array. Use std.algorithm.splitter if 
you want to avoid that copy.

to!float is going to create a float on the stack, so there's no heap alloction.

map is just a wrapper struct which sits on the stack. So, there's no copying 
going on there.

array is going to copy the data from map and allocate a new array, which is 
then appended to dat, which may or may not cause dat to be reallocated, 
depending on whether there are any slices after it or whatnot. In this 
particular case, it wouldn't have to, beacause dat is null, but you might as 
well assign it directly given the code that you give. If you're appending it 
to an array with actual data, then it depends on the state of that array as to 
whether reallocation is necessary. If you _really_ want to avoid reallocation 
in that case, then you'd do something more like

auto result = map!(to!float)(splitter(chompPrefix(s, "lno:")));
auto dat.reserve(walkLength(result));
foreach(e; result)
    dat ~= e;

though that would mean iterating over map twice, since map won't have length 
in this case (since splitter doesn't), which could actually result in worse 
performance, depending. But it does make it so that the only heap allocation 
that you might get is when calling reserve, and if dat happens to have a large 
enough capacity already, then there should be zero heap allocations here.

In most cases though, the single line is probably fine (especially if you 
change it to use splitter instead of split). I'd only do the second if I were 
really trying to eek all the performance out of it that I could.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list