Skip to content

Instantly share code, notes, and snippets.

@denkspuren
Last active December 19, 2017 15:44
Show Gist options
  • Save denkspuren/5b1a048bce056c478794007a1467377b to your computer and use it in GitHub Desktop.
Save denkspuren/5b1a048bce056c478794007a1467377b to your computer and use it in GitHub Desktop.
Thinking about the design of Markdown Excel (to be executed in JShell)
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
// This is a design proposal, see https://gist.github.com/denkspuren/c91b4dd9ffcc4c6040ce271e3fd7caa9
class Cell {
final int index;
final String value;
Cell(int index, String value) {
this.index = index;
this.value = value;
}
Cell updateValue(Object v) { // { return new Cell(index, v.toString()); }
return updateValue(v,"%s");
}
Cell updateValue(Object v, String fmt) {
return new Cell(index, new Formatter().format(Locale.US,fmt,v).toString());
}
public String toString() { return "(" + index + ":" + value + ")"; }
static String value(Cell c) { return c.value; }
static int index(Cell c) { return c.index; }
static ToDoubleFunction<Cell> toDouble = c -> Double.parseDouble(Cell.value(c));
static ToIntFunction<Cell> toInt = c -> Integer.parseInt(Cell.value(c));
static ToLongFunction<Cell> toLong = c -> Long.parseLong(Cell.value(c));
}
class Table {
static BiPredicate<Table,Cell> col(int col) {
return (BiPredicate<Table,Cell>) (t,c) ->
c.index % t.cols == (col >= 0 ? 0 : t.cols) + col % t.cols;
}
static BiPredicate<Table,Cell> row(int row) {
return (BiPredicate<Table,Cell>) (t,c) ->
c.index / t.cols == (row >= 0 ? 0 : t.rows) + row % t.rows;
}
static BiPredicate<Table,Cell> col(Cell cell) {
return (BiPredicate<Table,Cell>) (t,c) ->
c.index % t.cols == cell.index % t.cols;
}
static BiPredicate<Table,Cell> row(Cell cell) {
return (BiPredicate<Table,Cell>) (t,c) ->
c.index / t.cols == cell.index / t.cols;
}
final int rows, cols;
final String[] values;
Table(int cols, int rows, String... values) {
if (values.length != rows * cols) throw new IllegalArgumentException("size doesn't match cols * rows");
if (Arrays.stream(values).anyMatch(s -> s == null)) throw new IllegalArgumentException("table must not have null values");
this.cols = cols;
this.rows = rows;
this.values = Arrays.copyOf(values, values.length);
}
Stream<Cell> stream(BiPredicate<Table,Cell> p) {
return IntStream.range(0,values.length)
.mapToObj(i -> new Cell(i,values[i]))
.filter(c -> p.test(this,c));
}
Stream<Cell> stream(Predicate<Cell> p) { return stream((t,c) -> p.test(c)); }
Stream<Cell> stream() { return stream(c -> true); }
Table update(Cell cell) {
if (cell.index < 0 || cell.index >= values.length) throw new IllegalArgumentException("cell index is out of bounds");
String[] nvalues = Arrays.copyOf(values, values.length);
nvalues[cell.index] = cell.value;
return new Table(cols, rows, nvalues);
}
Table update(Stream<Cell> s) {
Collection<Cell> cells = s.collect(Collectors.toList());
Table t = this;
for(Cell c : cells) t = t.update(c);
return t;
}
}
Table t = new Table(
8,5,
"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Avg",
"1.0", "3.0", "4.0", "6.0", "6.0", "6.5", "4.0", "",
"2.3", "3.0", "4.0", "3.2", "6.0", "6.0", "4.0", "",
"1.0", "3.0", "4.1", "6.0", "6.0", "3.3", "2.0", "",
"4.7", "3.0", "4.0", "6.0", "6.0", "6.0", "4.0", ""
);
BiPredicate<Table,Cell> header = Table.row(0);
BiPredicate<Table,Cell> lastCol = Table.col(-1);
BiPredicate<Table,Cell> results = lastCol.and(header.negate());
BiPredicate<Table,Cell> data = lastCol.negate().and(header.negate());
Table tResult = t.update(
t.stream(results).map(result -> {
BiPredicate<Table,Cell> dataRow = data.and(Table.row(result));
double avg = t.stream(dataRow).collect(Collectors.averagingDouble(Cell.toDouble));
return result.updateValue(avg,"%.3f");
})
)
/* This is an alternative to compute `avg`
double sum = t.stream(dataRow).mapToDouble(Cell.toDouble).sum();
double count = t.stream(dataRow).count();
double avg = sum/count;
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment