score:4

Accepted answer

One approach could be to create a new 2D array from your two arrays to make it suitable for the standard nested selection pattern (see: http://bost.ocks.org/mike/nest/):

var arr1 = ['a', 'b', 'c'],
    arr2 = ['d', 'e', 'f'];

// prepare a 2D array
var data = arr1.map(function(v1) {
      return arr2.map(function(v2) {
        return v1 + v2;
      })
    });

d3.select("body").append("table")
  .selectAll("tr")
    .data(data)
  .enter().append("tr")
  .selectAll("td")
    .data(Object)
  .enter().append("td")
    .text(String);

Another approach is to make use of the fact that functions are being passed not only the index i of the element within the group, but also the index j of the group it belongs to:

var arr1 = ['a', 'b', 'c'],
    arr2 = ['d', 'e', 'f'];

d3.select("body").append("table")
  .selectAll("tr")
    // arr1 corresponds to the rows
    // bound data is not used in the td cells; only arr1.length is used
    .data(arr1)
  .enter().append("tr")
  .selectAll("td")
    // arr2 corresponds to the columns
    .data(arr2)
  .enter().append("td")
    .text(function(d, i, j) { return arr1[j] + d; }); // d === arr2[i]

A similar approach grabs the bound data from the group using parentNode instead of index j:

var arr1 = ['a', 'b', 'c'],
    arr2 = ['d', 'e', 'f'];

d3.select("body").append("table")
  .selectAll("tr")
    // arr1 corresponds to the rows
    .data(arr1)
  .enter().append("tr")
  .selectAll("td")
    // arr2 corresponds to the columns
    .data(arr2)
  .enter().append("td")
    .text(function(d) { return d3.select(this.parentNode).datum() + d; });

Related Query

More Query from same tag