1 module onsdata.table; 2 3 import std.stdio; 4 import std.string; 5 import std.conv; 6 7 import onsdata; 8 9 class Table(T) { 10 Row!T[] rows; 11 private string[] _columns; 12 size_t[string] colIndex; 13 14 this() { 15 } 16 this(size_t aWidth) { 17 width = aWidth; 18 } 19 this(size_t aWidth, size_t aHeight) { 20 this(aWidth); 21 height = aHeight; 22 } 23 this(size_t aHeight, string[] someColumns) { 24 this(someColumns.length, aHeight); 25 columns = someColumns; 26 } 27 this(S)(Table!S source, bool copy = false) { 28 columns = source.columns; 29 height = source.height; 30 foreach(i, row; source.rows) { 31 if (row) rows[i] = newRow; 32 if (copy) { 33 foreach(j, c; row.cells) rows[i][j] = to!T(c); 34 } 35 } 36 } 37 38 @property string[] columns() { return _columns; } 39 @property void columns(string[] values) { 40 _columns = values; 41 width(_columns.length); 42 foreach(i, col; columns) colIndex[col] = i; 43 } 44 45 @property void width(size_t aWidth) { _columns.length = aWidth; foreach(row; rows) if (row) row.width = width; } 46 @property size_t width() { return _columns.length; } 47 @property size_t height() { return rows.length; } 48 @property void height(size_t aHeight) { rows.length = aHeight; } 49 50 size_t count() { 51 size_t counter = 0; 52 foreach(row; rows) if (row) counter++; 53 return counter; 54 } 55 auto newRow() { 56 Row!T result = new Row!T(); 57 result.width = width; 58 return result; 59 } 60 auto newRow(T value) { 61 auto row = newRow; 62 row.value(value); 63 return row; 64 } 65 auto newRow(T[] values) { 66 auto row = newRow; 67 foreach(i, value; values) row[i] = value; 68 return row; 69 } 70 void add(Row!T row) { row.length = width; rows ~= row; } 71 72 auto firstRow() { 73 foreach(i, row; rows) if (row) return row; 74 return null; 75 } 76 size_t firstIndex() { 77 foreach(i, row; rows) if (row) return i; 78 return size_t.max; 79 } 80 size_t lastIndex() { 81 foreach_reverse(i, row; rows) if (row) return i; 82 return 0; 83 } 84 85 void opIndexAssign(Row!T row, size_t i) { 86 if (i < height) rows[i] = row; 87 } 88 auto opIndex(size_t i) { 89 if (i < height) return rows[i]; 90 return newRow; // blää 91 } 92 size_t opIndex(string col) { 93 return colIndex[col]; 94 } 95 96 void min(size_t target, size_t[] cols) { foreach(row; rows) if (row) row.min(target, cols); } 97 T min(size_t col, size_t start, size_t end) { 98 bool first = false; 99 T result = 0; 100 foreach(row; rows) { 101 if (row) { 102 if (!first) { 103 result = row[col]; 104 first = true; 105 } 106 else { 107 if (result > row[col]) result = row[col]; 108 } 109 } 110 } 111 return result; 112 } 113 114 void avg(size_t target, size_t[] cols) { foreach(row; rows) if (row) row.avg(target, cols); } 115 T avg(size_t col, size_t start, size_t end) { 116 size_t counter = 0; 117 T result = 0; 118 foreach(i; start..end) if (auto row = this[i]) { 119 counter++; 120 result += row[col]; 121 } 122 if (counter) return to!T(result/counter); 123 return 0; 124 } 125 126 void max(size_t target, size_t[] cols, size_t start = 0, size_t end = 0) { 127 auto e = (end == 0 ? height : end); 128 foreach(i; start..end) if (auto row = this[i]) row.max(target, cols); } 129 T max(size_t col, size_t start = 0, size_t end = 0) { 130 auto e = (end == 0 ? height : end); 131 bool first = false; 132 T result = 0; 133 foreach(i; start..end) if (auto row = this[i]) { 134 if (!first) { 135 result = row[col]; 136 first = true; 137 } 138 else { 139 if (result < row[col]) result = row[col]; 140 } 141 } 142 return result; 143 } 144 145 void sum(size_t target, size_t[] cols) { foreach(row; rows) if (row) row.sum(target, cols); } 146 /++ 147 Sum - Calculating sum of columns in a row 148 +/ 149 S sum(S = double)(size_t col, size_t start = 0, size_t end = 0) { 150 auto e = (end == 0 ? height : end); 151 int counter = 0; double result = 0; 152 if (end > height) end = height; 153 foreach(i; start..e) if (auto row = this[i]) { 154 counter++; result += row[col]; } 155 return to!S((counter) ? result/counter : 0); 156 } 157 // bool sum(T)(T[][] table, size_t target, size_t[] colInds, size_t start = 0, size_t end = size_t.max) { 158 // if (table.length == 0) return false; 159 // if (colInds.length == 0) return false; 160 // 161 // if (end > table.length) end = table.length; 162 // auto rlen = table[0].length-1; // max Value for colInds 163 // if (target > rlen) return false; 164 // foreach(cIndex; colInds) if (cIndex > rlen) return false; 165 // 166 // double sum = row[cols[0]]; 167 // foreach(i; start..end) if (auto row = table[i]) { 168 // if (cols.length > 1) foreach(col; cols[1..$]) sum += row[col]; 169 // row[target] = check!T(sum/cols.length); 170 // } 171 // return true; 172 // } 173 174 void delta(string target, string[2] cols, size_t start = 0, size_t end = 0) { delta(this[target], cols, start, end); } 175 void delta(size_t target, string[2] cols, size_t start = 0, size_t end = 0) { delta(target, [this[cols[0]], this[cols[1]]], start, end); } 176 void delta(string target, size_t[2] cols, size_t start = 0, size_t end = 0) { delta(this[target], cols, start, end); } 177 void delta(size_t target, size_t[2] cols, size_t start = 0, size_t end = 0) { 178 auto e = (end == 0 ? height : end); 179 foreach(i; start..e) if (auto row = this[i]) row.delta(target, cols); } 180 181 S inc(S = double)(size_t col, size_t start = 0, size_t end = 0) { 182 auto e = (end == 0 ? height : end); 183 int counter = 0; int x = 0; bool foundFirst = false; 184 foreach(i; start..e) if (auto row = this[i]) { 185 if (i == 0) continue; 186 187 if ((rows[i-1]) && (foundFirst)) { 188 double delta = row[col] - rows[i-1][col]; 189 if (delta > 0) x++; 190 counter++; 191 } 192 else foundFirst = true; 193 } 194 if (counter) return to!S(x/counter); 195 return 0; 196 } 197 198 // -- dec 199 S dec(S = double)(size_t col, size_t start = 0, size_t end = 0) { 200 auto e = (end == 0 ? height : end); 201 int counter = 0; int x = 0; bool foundFirst = false; 202 foreach(i; start..e) if (auto row = this[i]) { 203 if (i == 0) continue; 204 205 if ((foundFirst) && (this[i-1])) { 206 double delta = row[col] - this[i-1][col]; 207 if (delta < 0) x++; 208 counter++; 209 } 210 else foundFirst = true; 211 } 212 if (counter) return x/counter; 213 return 0; 214 } 215 216 // -- div 217 S div(S = double)(size_t col, size_t start = 0, size_t end = 0) { 218 auto e = (end == 0 ? height : end); 219 T[] values; 220 foreach(i; start..e) if (auto row = this[i]) { 221 if (auto row2 = this[i-1]) { 222 values ~= row2[col] - row[col]; 223 } 224 } 225 if (values) { 226 S result = 0; 227 foreach(value; values) result += value; 228 return result/values.length; 229 } 230 return 0; 231 } 232 233 Table!T copy() { return new Table!T(this); } 234 override string toString() { 235 string result; 236 result ~= "width:%s\theight:%s\n".format(width, height); 237 foreach(i, row; rows) if (row) result ~= "%s:\t%s\n".format(i, row.toString); 238 return result; 239 } 240 241 T[string][] changedRows(Table!T originalTable) { 242 T[string][] results; results.length = height; 243 foreach(i, row; rows) if (row) results[i] = changedCells(i, originalTable); 244 return results; 245 } 246 247 T[string][] changedRows(T originalValue) { 248 T[string][] results; results.length = height; 249 foreach(i, row; rows) if (row) results[i] = changedCells(i, originalValue); 250 return results; 251 } 252 253 T[string] changedCells(size_t i, Table!T originalTable) { 254 T[string] result; 255 if (auto row = rows[i]) { 256 if (auto oRow = originalTable[i]) { 257 foreach(k, v; colIndex) { 258 if (row[v] != oRow[v]) result[k] = row[v]; 259 } 260 } 261 } 262 return result; 263 } 264 T[string] changedCells(size_t i, T originalValue) { 265 T[string] result; 266 if (auto row = rows[i]) { 267 foreach(k, v; colIndex) { 268 if (row[v] != originalValue) result[k] = row[v]; 269 } 270 } 271 return result; 272 } 273 274 }