1 module dataframes.rows; 2 3 import std.traits; 4 import std.conv : text; 5 import std.range; 6 import std.format; 7 import std.variant; 8 import core.exception; 9 import std.datetime; 10 import std.json; 11 12 import dataframes; 13 14 struct Row(T) 15 { 16 DataFrame!T df; 17 size_t index; 18 19 alias fieldNames = FieldNameTuple!(T); 20 alias fieldTypes = FieldTypeTuple!(T); 21 22 static foreach(idx, name; fieldNames) 23 { 24 // For each DataFrame column, add a function to access the 25 // row by name. For example, 26 // double price() { return this.df.price[this.rowIndex]; } 27 mixin(i"$(fieldTypes[idx].stringof) $(name)() {return this.df.$(name)[this.index];}".text); 28 } 29 30 /** 31 * Access the column by label 32 */ 33 Variant opIndex(string label) 34 { 35 Variant output; 36 s1: switch (label) 37 { 38 static foreach(name; fieldNames) 39 { 40 mixin("case \"" ~ name ~ "\": output = this.df." ~ name ~ "[this.index]; break s1;"); 41 } 42 default: 43 throw new RangeError("invalid label"); 44 } 45 return output; 46 } 47 48 /** 49 Access the column by index 50 */ 51 Variant opIndex(size_t idx) 52 { 53 return opIndex(this.df.columnNames[idx]); 54 } 55 56 string toString() 57 { 58 auto output = appender!string; 59 60 output ~= format("Row(index=%s", this.index); 61 62 static foreach(name; fieldNames) 63 { 64 static if(isNumeric!(typeof( __traits(getMember, this.df, name).values[0]))) 65 { 66 if (is(typeof( __traits(getMember, this.df, name).values[0]) == double)) 67 output.put(format(", %.2f", __traits(getMember, this.df, name).values[index])); 68 else 69 output.put(format(", %s", __traits(getMember, this.df, name).values[index])); 70 } 71 else 72 output.put(format(", %s", __traits(getMember, this.df, name).values[index])); 73 } 74 75 return output.data ~ ")"; 76 } 77 78 T1 toDataFrameStruct(T1)() 79 { 80 alias outputFieldNames = FieldNameTuple!(T1); 81 T1 output; 82 83 static foreach(name; outputFieldNames) 84 { 85 static if(hasMember!(T, name)) 86 __traits(getMember, output, name) = __traits(getMember, this, name); 87 } 88 89 return output; 90 } 91 92 JSONValue toJSON() 93 { 94 JSONValue rowdata; 95 static foreach(name; fieldNames) 96 mixin("rowdata[name] = this." ~ name ~ ";"); 97 98 return rowdata; 99 } 100 } 101 102 DataFrame!T toDataFrame(T, Range)(Range rows) 103 { 104 auto df = new DataFrame!T; 105 106 foreach(row; rows) 107 df.add(row.toDataFrameStruct!T); 108 109 return df; 110 }