Thread overview | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 15, 2015 Casting MapResult | ||||
---|---|---|---|---|
| ||||
I wrote a simple function to apply map to a float dynamic array auto exp(float[] x) { auto y = x.map!(a => exp(a)); return y; } However, the type of the result is MapResult!(__lambda2, float[]). It seems like some of the things that I might do to a float[], I can't do to this type, like adding them together. So I tried to adjust this by adding in a cast to float[], as in float[] exp(float[] x) { auto y = x.map!(a => exp(a)); cast(float[]) y; return y; } But I get an error that I can't convert MapResult!(__lambda2, float[]) to float[]. So I suppose I have two questions: 1) am I screwing up the cast, or is there no way to convert the MapResult to float[], 2) should I just not bother with map (I wrote an alternate, longer, version that doesn't use map but returns float[] properly). |
June 15, 2015 Re: Casting MapResult | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 Attachments: | On Mon, 15 Jun 2015 15:10:20 +0000, jmh530 wrote: you shouldn't cast it like that. use `std.array.array` to get the actual array. like this: import std.array; auto y = x.map!(a => exp(a)).array; the thing is that `map` returns so-called "lazy range". lazy ranges trying to not do any work until they are explicitely asked. i.e. y = x.map!(a => exp(a)) doesn't do any real processing yet, it only prepares everything for it. and only when you're calling `y.front`, `map` is processing one element. only one, as it has no need to process next until you call `popFront`. tl;dr: you can't simply cast that lazy range back to array, you have to use `std.std.array` to get the array from it. |
June 15, 2015 Re: Casting MapResult | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Mon, 15 Jun 2015 15:10:20 +0000, jmh530 wrote:
> So I suppose I have two questions: 1) am I screwing up the cast, or is there no way to convert the MapResult to float[], 2) should I just not bother with map (I wrote an alternate, longer, version that doesn't use map but returns float[] properly).
MapResult is a wrapper around your original range that performs the mapping operation lazily. If you want eagerly evaluate and get back to an array use the std.array.array function:
import std.array : array;
auto y = x.map!(a => exp(a)).array;
Or if you have already allocated an array of the appropriate size you can use std.algorithm.copy:
import std.algorithm : copy;
float[] y = new float[](appropriate_length);
x.map!(a => exp(a)).copy(y);
|
June 15, 2015 Re: Casting MapResult | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Monday, 15 June 2015 at 15:10:24 UTC, jmh530 wrote:
> So I suppose I have two questions: 1) am I screwing up the cast, or is there no way to convert the MapResult to float[]
Don't cast it, just slap a .array on the end after importing std.range. Like so:
import std.algorithm;
import std.range; // add this line somewhere
float[] exp2(float[] x) {
auto y = x.map!(a => exp(a));
return y.array; // this line changed to make the array
}
The reason is that map returns a lazy generator instead of an array directly. It only evaluates on demand.
To get it to evaluate and save into an array, the .array function is called.
Tip though: don't call .array if you don't have to, chaining calls to map and such, even foreach(item; some_map_result) can be done without actually building the array and can give more efficiency.
|
June 15, 2015 Re: Casting MapResult | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Monday, 15 June 2015 at 15:10:24 UTC, jmh530 wrote:
> float[] exp(float[] x) {
> auto y = x.map!(a => exp(a));
> cast(float[]) y;
> return y;
> }
>
> But I get an error that I can't convert MapResult!(__lambda2, float[]) to float[].
>
> So I suppose I have two questions: 1) am I screwing up the cast, or is there no way to convert the MapResult to float[], 2) should I just not bother with map (I wrote an alternate, longer, version that doesn't use map but returns float[] properly).
First off: Don't cast unless you know exactly what you're doing. It's easy to stumble into undefined behaviour land with casts.
To answer the question: You can convert from from MapResult to float[], but not with a cast. Instead, use std.array.array:
import std.array: array;
return x.map!(std.math.exp).array;
|
June 15, 2015 Re: Casting MapResult | ||||
---|---|---|---|---|
| ||||
Posted in reply to jmh530 | On Monday, 15 June 2015 at 15:10:24 UTC, jmh530 wrote:
> <snip>
> float[] exp(float[] x) {
> auto y = x.map!(a => exp(a));
> cast(float[]) y;
> return y;
> }
>
Also, I dont think your functions will work?
Your recursively calling "exp" in your map, but with a 'float' instead of 'float[]'.
|
June 15, 2015 Re: Casting MapResult | ||||
---|---|---|---|---|
| ||||
Posted in reply to anonymous | Thank you all for the very fast answers. It looks like that works. |
June 15, 2015 Re: Casting MapResult | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On 06/15/2015 08:21 AM, Adam D. Ruppe wrote: > don't call .array if you don't have to, chaining calls to > map and such, even foreach(item; some_map_result) can be done without > actually building the array and can give more efficiency. To add, the OP can use 'sum' or 'reduce' for "adding them together": http://dlang.org/phobos/std_algorithm_iteration.html import std.stdio; import std.algorithm; import std.math; void main() { float[] arr = [ 1.5, 2.5 ]; auto y = arr.map!exp; writeln(y.sum); // same as sum(y) } An equivalent of the last line: writeln(reduce!((result, a) => result + a)(y)); Ali |
June 15, 2015 Re: Casting MapResult | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Monday, 15 June 2015 at 16:16:00 UTC, Ali Çehreli wrote:
> On 06/15/2015 08:21 AM, Adam D. Ruppe wrote:
>
> > don't call .array if you don't have to, chaining calls to
> > map and such, even foreach(item; some_map_result) can be done
> without
> > actually building the array and can give more efficiency.
>
> To add, the OP can use 'sum' or 'reduce' for "adding them together":
>
> http://dlang.org/phobos/std_algorithm_iteration.html
>
> import std.stdio;
> import std.algorithm;
> import std.math;
>
> void main()
> {
> float[] arr = [ 1.5, 2.5 ];
> auto y = arr.map!exp;
> writeln(y.sum); // same as sum(y)
> }
>
> An equivalent of the last line:
>
> writeln(reduce!((result, a) => result + a)(y));
>
> Ali
`sum` is better for floating-point ranges, because it uses pair-wise or Kahan summation if possible, in order to preserve precision.
|
June 15, 2015 Re: Casting MapResult | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On 06/15/2015 09:39 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote: >> writeln(y.sum); // same as sum(y) >> } >> >> An equivalent of the last line: >> >> writeln(reduce!((result, a) => result + a)(y)); > `sum` is better for floating-point ranges, because it uses pair-wise or > Kahan summation if possible, in order to preserve precision. Good point. I had mentioned that elsewhere after learning about it recently: "the sum of the elements of a range should be calculated by std.algorithm.sum, which uses special algorithms to achieve more accurate calculations for floating point types." :) http://ddili.org/ders/d.en/fibers.html#ix_fibers.recursion Ali |
Copyright © 1999-2021 by the D Language Foundation