Allow objects as input to d3_dsv.format.

The previous implementation of format, which only supported arrays as input, is
retained as d3_dsv.formatRows; for backwards-compatibility, d3_dsv.format allows
both arrays and objects as input (to be removed in 4.0). This change makes
format and formatRows symmetric with parse and parseRows, respectively.

To compute the set of fields from all objects, two passes are required. Fields
are listed in discovery order, so that in the common case where all fields are
defined on all objects, the order of columns in the generated DSV will match the
property iteration order of the first object.

This supersedes #1106 and fixes #509; thank you to @smcgivern and @hammer for
suggesting this feature.
This commit is contained in:
Mike Bostock 2013-03-07 07:45:00 -08:00
Родитель 8b703e22c2
Коммит fe09bb0cc2
5 изменённых файлов: 68 добавлений и 7 удалений

18
d3.js поставляемый
Просмотреть файл

@ -1091,7 +1091,7 @@ d3 = function() {
return name == "transform" ? d3.interpolateTransform : d3.interpolate;
}
d3.interpolators = [ d3.interpolateObject, function(a, b) {
return b instanceof Array && d3.interpolateArray(a, b);
return Array.isArray(b) && d3.interpolateArray(a, b);
}, function(a, b) {
return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + "");
}, function(a, b) {
@ -5416,6 +5416,22 @@ d3 = function() {
return rows;
};
dsv.format = function(rows) {
if (Array.isArray(rows[0])) return dsv.formatRows(rows);
var fieldSet = new d3_Set(), fields = [];
rows.forEach(function(row) {
for (var field in row) {
if (!fieldSet.has(field)) {
fields.push(fieldSet.add(field));
}
}
});
return [ fields ].concat(rows.map(function(row) {
return fields.map(function(field) {
return formatValue(row[field]);
}).join(delimiter);
})).join("\n");
};
dsv.formatRows = function(rows) {
return rows.map(formatRow).join("\n");
};
function formatRow(row) {

10
d3.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -254,7 +254,7 @@ function d3_interpolateByName(name) {
d3.interpolators = [
d3.interpolateObject,
function(a, b) { return b instanceof Array && d3.interpolateArray(a, b); },
function(a, b) { return Array.isArray(b) && d3.interpolateArray(a, b); },
function(a, b) { return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + ""); },
function(a, b) { return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Color) && d3.interpolateRgb(a, b); },
function(a, b) { return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b); }

Просмотреть файл

@ -98,6 +98,26 @@ function d3_dsv(delimiter, mimeType) {
};
dsv.format = function(rows) {
if (Array.isArray(rows[0])) return dsv.formatRows(rows); // deprecated; use formatRows
var fieldSet = new d3_Set, fields = [];
// Compute unique fields in order of discovery.
rows.forEach(function(row) {
for (var field in row) {
if (!fieldSet.has(field)) {
fields.push(fieldSet.add(field));
}
}
});
return [fields].concat(rows.map(function(row) {
return fields.map(function(field) {
return formatValue(row[field]);
}).join(delimiter);
})).join("\n");
};
dsv.formatRows = function(rows) {
return rows.map(formatRow).join("\n");
};

Просмотреть файл

@ -160,6 +160,31 @@ suite.addBatch({
topic: function() {
return d3.csv.format;
},
"takes an array of objects as input": function(format) {
assert.equal(format([{a: 1, b: 2, c: 3}]), "a,b,c\n1,2,3");
},
"computes the union of all fields": function(format) {
assert.equal(format([
{a: 1},
{a: 1, b: 2},
{a: 1, b: 2, c: 3},
{b: 1, c: 2},
{c: 1}
]), "a,b,c\n1,,\n1,2,\n1,2,3\n,1,2\n,,1");
},
"orders field by first-seen": function(format) {
assert.equal(format([
{a: 1, b: 2},
{c: 3, b: 4},
{c: 5, a: 1, b: 2}
]), "a,b,c\n1,2,\n,4,3\n1,2,5");
}
},
"formatRows": {
topic: function() {
return d3.csv.formatRows;
},
"takes an array of arrays as input": function(format) {
assert.equal(format([["a", "b", "c"], ["1", "2", "3"]]), "a,b,c\n1,2,3");
},