I've also had to do something like that in the past and what I ended up with was adding my own map method to the d3.selection prototype, like this:
// Return a new array by collecting the results of the specified function
// for each element in the current selection, passing in the current datum d
// and index i, with the this context of the current DOM element.
d3.selection.prototype.map_flat = function(f) {
var arr = [];
this.each(function(d, i) {
arr[arr.length] = f.call(this, d, i);
});
return arr;
};
However, this creates a flat array based on the current selection. In your, and the more general, case you'd like a nested version like this:
// Return a new nested array by collecting the results of the specified function
// for each element in the current selection, passing in the current datum d
// and indexes i and j with the this context of the current DOM element.
d3.selection.prototype.map_nested = function(f) {
var arr = d3.range(this.length).map(function() { return []; });
this.each(function(d, i, j) {
arr[j].push(f.call(this, d, i, j));
});
return arr;
};
You can use this as follows:
// make nested selection
var tds = d3.select("tbody").selectAll("tr").selectAll("td");
// obtain nested array containing the text of each table cell
var vals = tds.map_nested(function(d, i, j) { return d3.select(this).text(); });
Tore