www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Most elegant way for split array of struct into components

reply Miguel L <mlabayru gmail.com> writes:
Hello
I would like advice in the most elegant way for doing this in D:

I have something like this:

struct A
{
int x;
int y;
}

A[] my_array;

And I would need something like this:

assert( my_array[0..n].x == [ my_array[0].x, my_array[1].x, ... 
my_array[n-1].x ]);
assert( my_array[0..n].y == [ my_array[0].y, my_array[1].y, ... 
my_array[n-1].y ]);
assert( my_array.x == [ my_array[0].x, my_array[1].x, ... 
my_array[$-1].x ]);
assert( my_array.y == [ my_array[0].y, my_array[1].y, ... 
my_array[$-1].y ]);

Is it possible to implement something like this in D? If not, 
which would be the best way to get an array of x or y component 
of my_array?

Thank you
Jul 04 2016
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 07/04/2016 11:07 PM, Miguel L wrote:

 struct A
 {
 int x;
 int y;
 }
 would be the best way to get an array of x or y component of my_array?
The simplest is to pick the element by std.algorithm.map: import std.stdio; import std.range; import std.array; import std.algorithm; struct A { int x; int y; } void main() { A[] my_array = iota(3) .map!(i => A(i, 11 * i)) .array; writeln("The whole array:"); writeln(my_array); writeln("Just the x members"); auto xs = my_array.map!(a => a.x); writeln(xs); writeln("Just the y members"); auto ys = my_array.map!(a => a.y); writeln(ys); } Prints The whole array: [A(0, 0), A(1, 11), A(2, 22)] Just the x members [0, 1, 2] Just the y members [0, 11, 22] map has a shortcut: If there is a function foo that takes A, then you can do just this: writeln(my_array.map!foo); (foo can be a member function or a non-member function.) With the great risk of polluting the namespace, here is a draft of creating non-member accessor functions automatically: string memberAccessors(T)() { import std.string; string accessors; foreach(m; __traits(allMembers, T)) { accessors ~= format("auto %s(%s a) { return a.%s; }\n", m, T.stringof, m); } return accessors; } mixin(memberAccessors!A); That generates and mixes in accessor functions for each member. A pragma(msg) can show what is generated: pragma(msg, memberAccessors!A); Prints at compile time: auto x(A a) { return a.x; } auto y(A a) { return a.y; } (Crazy idea. :) ) But then, it's as simple as the following: writeln(my_array.map!y); Ali
Jul 05 2016
parent reply Miguel L <mlabayru gmail.com> writes:
On Tuesday, 5 July 2016 at 07:33:40 UTC, Ali Çehreli wrote:
 On 07/04/2016 11:07 PM, Miguel L wrote:

 [...]
 [...]
my_array? The simplest is to pick the element by std.algorithm.map: [...]
Thank you Ali, that works. On the same subject, could it be possible to implement some class or struct method that works on an array of objects of that class or method? class A { void Y(A[] a){...} } A[] array; array.Y(); Sorry for my ignorance, i am just starting to work in D.
Jul 05 2016
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 07/05/2016 01:10 AM, Miguel L wrote:

 could it be possible to implement some class or
 struct method that works on an array of objects of that class or method?

 class A
 {
 void Y(A[] a){...}
 }

 A[] array;
 array.Y();
Yes, but that normally belongs outside the type. Luckily, D's UFCS feauter lets one call a non-member function as if it's a member function: import std.stdio; import std.algorithm; import std.range; class A { int i; this(int i) { this.i = i; } } // Not a member: void Y(A[] a){ foreach (e; a) { writefln("working with %s", e.i); } } void main() { A[] array = iota(5).map!(i => new A(i)).array; // Can be called like a member: array.Y(); } Still, it's debatable whether an array-processing functions should be executed with the member function syntax. I would write Y(array). When you discover the ranges, you will realize that instead of defining functions like Y that contain explicit loops, combining functions that work with just a single A is more maintainable, scalable, and almost always faster (sometimes you won't need to hold actual arrays of anything). void y(A a) { writefln("working with %s", a.i); } void main() { // Objects are created but not a single array is in sight: iota(5) .map!(i => new A(i)) .each!y; } The output is the same: working with 0 working with 1 working with 2 working with 3 working with 4 Ali
Jul 05 2016