www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Templates and Associative Arrays

reply dsimcha <dsimcha yahoo.com> writes:
Is it possible to create a template function that treats regular dynamic
arrays the same as associative arrays?  For example, I want to create a very
simple template function to extract a column from a 2-d array of T's.  If the
array is non-associative in both dimensions, the function could be trivially
implemented as:

T[] extract_column(T)(T[][] data, size_t column_to_extract)
{
    T[] extracted_column;
    foreach(row; data)
    {
        extracted_column~=row[column_to_extract];
    }
    return extracted_column;
}

However, in the case of an associatve array, I cannot think of any obvious way
to make this work without essentially implementing it four different times,
once each for an associative and non-associative row dimension and likewise
for the column dimension.
Jan 20 2008
next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
dsimcha <dsimcha yahoo.com> wrote:

 Is it possible to create a template function that treats regular dynam=

 arrays the same as associative arrays?  For example, I want to create =

 very
 simple template function to extract a column from a 2-d array of T's. =

 If the
 array is non-associative in both dimensions, the function could be  =

 trivially
 implemented as:

 T[] extract_column(T)(T[][] data, size_t column_to_extract)
 {
     T[] extracted_column;
     foreach(row; data)
     {
         extracted_column~=3Drow[column_to_extract];
     }
     return extracted_column;
 }

 However, in the case of an associatve array, I cannot think of any  =

 obvious way
 to make this work without essentially implementing it four different  =

 times,
 once each for an associative and non-associative row dimension and  =

 likewise
 for the column dimension.

If you're asking whether there is some uniform way to declare an = associative and a normal dynamic array, then I fear you're out of luck. = = Perhaps this should be possible by some strange magic like int[void] foo= ; = to declare a normal array... I did make a template that works though, but it's an ugly way to do this= : template foo(T, U, V) { mixin("T[] extract_column(T[" ~ ((U.stringof =3D=3D "void")?"":U.string= of) ~ = "][" ~ ((V.stringof =3D=3D "void")?"":V.stringof) ~ "] data, size_t = column_to_extract) { T[] extracted_column; foreach(row; data) { extracted_column~=3Drow[column_to_extract]; } return extracted_column; }"); } alias foo!(int, void, void) bar; int main() { int[][] baz; baz.length =3D 1; baz[0].length =3D 1; baz[0][0] =3D 4; auto foobar =3D bar.extract_column(baz, 0); writefln(foobar); = return 0; } prints [4] This might be possible to do in a better way, of course. Simen Kjaeraas
Jan 20 2008
prev sibling parent reply downs <default_357-line yahoo.de> writes:
dsimcha wrote:
 Is it possible to create a template function that treats regular dynamic
 arrays the same as associative arrays?  For example, I want to create a very
 simple template function to extract a column from a 2-d array of T's.  If the
 array is non-associative in both dimensions, the function could be trivially
 implemented as:
 
 T[] extract_column(T)(T[][] data, size_t column_to_extract)
 {
     T[] extracted_column;
     foreach(row; data)
     {
         extracted_column~=row[column_to_extract];
     }
     return extracted_column;
 }
 
 However, in the case of an associatve array, I cannot think of any obvious way
 to make this work without essentially implementing it four different times,
 once each for an associative and non-associative row dimension and likewise
 for the column dimension.

Sure :) Keep in mind, this code isn't tested .. but it should work in theory. template Init(T) { T Init; } import std.traits; template NestedArrayElemType(T) { // this uses return-type autodeduction to basically say "if we iterated over the elements of T, and returned elem2; what would its type be?" alias ReturnType({ foreach (elem; Init!(T)) foreach (elem2; elem) return elem2; }) NestedArrayElemType; } alias NestedArrayElemType naet; naet!(T) extract_column(T)(T data, size_t which) { naet!(T) res; foreach (row; data) res ~= row[which]; return res; } --downs
Jan 21 2008
parent reply downs <default_357-line yahoo.de> writes:
Agh. Too many mistakes. Sorry.
Here's some working, tested code instead.

 import std.stdio, std.traits;
 
 template Init(T) { T Init; }
 
 template NAET(T) {
   alias ReturnType!({ foreach (elem; Init!(T)) foreach (elem2; elem) return
elem2; }) NAET;
 }
 
 void main() {
   writefln(NAET!(int[][]).stringof);
   writefln(NAET!(int[][int]).stringof);
   writefln(NAET!(float[string][]).stringof);
 }

Hope it helps. --downs
Jan 21 2008
parent reply dsimcha <dsimcha yahoo.com> writes:
Wow, that is an impressive hack.  While it's certainly better than nothing, this
is one area where it would be nice if the template system in D improved to make
this cleaner and more obvious.  I am trying to learn/use D to replace scripting
languages for programs involving huge CSV files, because the scripting languages
are painfully slow for this.  I have a small custom library in PHP (which I use
for general-purpose, not just web, scripting) for handling CSVs, and am trying
to
port it to D, and creating simple, clean templates for processing arrays without
knowing at compile time whether they are regular or associative is a major
hangup.
Jan 21 2008
parent reply downs <default_357-line yahoo.de> writes:
dsimcha wrote:
 Wow, that is an impressive hack.  While it's certainly better than nothing,
this
 is one area where it would be nice if the template system in D improved to make
 this cleaner and more obvious.  I am trying to learn/use D to replace scripting
 languages for programs involving huge CSV files, because the scripting
languages
 are painfully slow for this.  I have a small custom library in PHP (which I use
 for general-purpose, not just web, scripting) for handling CSVs, and am trying
to
 port it to D, and creating simple, clean templates for processing arrays
without
 knowing at compile time whether they are regular or associative is a major
hangup.

Alright, so here's the boring version :)
 
 import std.stdio;
 
 template Init(T) { T Init; }
 
 template ElemType(T) {
   static if (is(typeof(Init!(T).keys)))
     alias typeof(Init!(T)[Init!(T).keys[0]]) ElemType;
   else
     alias typeof(Init!(T)[0]) ElemType;
 }
 
 void main() {
   writefln(ElemType!(ElemType!(int[][])).stringof);
   writefln(ElemType!(ElemType!(float[string][string])).stringof);
   writefln(ElemType!(ElemType!(real[float][])).stringof);
 }

--downs
Jan 22 2008
parent reply Don Clugston <dac nospam.com.au> writes:
downs wrote:
 dsimcha wrote:
 Wow, that is an impressive hack.  While it's certainly better than nothing,
this
 is one area where it would be nice if the template system in D improved to make
 this cleaner and more obvious.  I am trying to learn/use D to replace scripting
 languages for programs involving huge CSV files, because the scripting
languages
 are painfully slow for this.  I have a small custom library in PHP (which I use
 for general-purpose, not just web, scripting) for handling CSVs, and am trying
to
 port it to D, and creating simple, clean templates for processing arrays
without
 knowing at compile time whether they are regular or associative is a major
hangup.

Alright, so here's the boring version :)
 import std.stdio;

 template Init(T) { T Init; }

 template ElemType(T) {
   static if (is(typeof(Init!(T).keys)))
     alias typeof(Init!(T)[Init!(T).keys[0]]) ElemType;
   else
     alias typeof(Init!(T)[0]) ElemType;
 }

 void main() {
   writefln(ElemType!(ElemType!(int[][])).stringof);
   writefln(ElemType!(ElemType!(float[string][string])).stringof);
   writefln(ElemType!(ElemType!(real[float][])).stringof);
 }

--downs

Do you really need the Init template ? Why not just: template ElemType(T) { static if (is(typeof(T.keys))) alias typeof(T[T.keys[0]]) ElemType; else alias typeof(T[0]) ElemType; }
Jan 22 2008
parent downs <default_357-line yahoo.de> writes:
Don Clugston wrote:
 Do you really need the Init template ? Why not just:
 
 template ElemType(T) {
   static if (is(typeof(T.keys)))
     alias typeof(T[T.keys[0]]) ElemType;

Thanks. I wasn't aware that you could use types like that. Kind of unintuitive, don't you think? :) --downs
Jan 22 2008