如何将嵌套对象数组转换为 CSV?
How to convert array of nested objects to CSV?
我有一个包含嵌套对象的数组,例如这个:
[
{"name": "1", "children": [{"name": "1.1", "children":"1.2"}]},
{"id": "2", "thing": [{"name": "2.1", "children":"2.2"}]},
{"name": "3", "stuff": [{"name": "3.1", "children":"3.2"}]},
]
对象可以包含不同类型的值,包括其他嵌套对象。
我想将此数组转换为 CSV 格式。
我尝试使用 for .. in
循环、常规嵌套 for
循环、.map()
和递归进行迭代。不过,我认为递归可能是解决这个特定问题的唯一方法。对于 CSV 字段名称,我想使用指向该值的键序列。
对于给定的示例,我要查找的 CSV 结果是:
name, children.name, children.children,id, thing.name, thing.children, stuff.name, stuff.children
1, 1.1, 1.2,
,,,2,2.1,2.2
3,,,,3,3.1,3.2
您可以使用此 ES6 函数创建您正在寻找的二维数组,然后您可以轻松地将其转换为 CSV:
function pivot(arr) {
var mp = new Map();
function setValue(a, path, val) {
if (Object(val) !== val) { // primitive value
var pathStr = path.join('.');
var i = (mp.has(pathStr) ? mp : mp.set(pathStr, mp.size)).get(pathStr);
a[i] = val;
} else {
for (var key in val) {
setValue(a, key == '0' ? path : path.concat(key), val[key]);
}
}
return a;
}
var result = arr.map( obj => setValue([], [], obj) );
return [[...mp.keys()], ...result];
}
function toCsv(arr) {
return arr.map( row =>
row.map ( val => isNaN(val) ? JSON.stringify(val) : +val ).join(',')
).join('\n');
}
// Sample data
var arr = [
{"name": "1", "children": [{"name": "1.1", "children":"1.2"}]},
{"id": "2", "thing": [{"name": "2.1", "children":"2.2"}]},
{"name": "3", "stuff": [{"name": "3.1", "children":"3.2"}]},
];
// Conversion to 2D array and then to CSV:
console.log(toCsv(pivot(arr)));
.as-console-wrapper { max-height: 100% !important; top: 0; }
有关将二维数组转换为 CSV 的其他方法,请参阅此 Q&A。
这是一个 ES5 提案。
您可以迭代数组并将键收集到散列中 table 并稍后使用间隙存储数据。
var data = [{ name: "1", children: [{ name: "1.1", children: "1.2" }] }, { id: "2", thing: [{ name: "2.1", children: "2.2" }] }, { name: "3", stuff: [{ name: "3.1", children: "3.2" }] }],
csv = function (array) {
var cols = [],
collection = Object.create(null),
i = -1,
toCSV = function (v) { return isNaN(v)? JSON.stringify(v): v; },
csv;
array.forEach(function iter(path) {
return function (o) {
path.length || i++;
Object.keys(o).forEach(function (k) {
if (Array.isArray(o[k])) {
o[k].forEach(iter(path.concat(k)));
return;
}
var key = path.concat(k).join('.');
if (!collection[key]) {
cols.push(key);
collection[key] = [];
}
collection[key][i] = o[k];
});
};
}([]));
csv = cols.map(toCSV).join() + '\n';
for (i = 0; i < array.length; i++) {
csv += cols.map(function (k) { return toCSV(collection[k][i]); }).join() + '\n';
}
return csv;
}(data);
console.log(csv);
我有一个包含嵌套对象的数组,例如这个:
[
{"name": "1", "children": [{"name": "1.1", "children":"1.2"}]},
{"id": "2", "thing": [{"name": "2.1", "children":"2.2"}]},
{"name": "3", "stuff": [{"name": "3.1", "children":"3.2"}]},
]
对象可以包含不同类型的值,包括其他嵌套对象。
我想将此数组转换为 CSV 格式。
我尝试使用 for .. in
循环、常规嵌套 for
循环、.map()
和递归进行迭代。不过,我认为递归可能是解决这个特定问题的唯一方法。对于 CSV 字段名称,我想使用指向该值的键序列。
对于给定的示例,我要查找的 CSV 结果是:
name, children.name, children.children,id, thing.name, thing.children, stuff.name, stuff.children
1, 1.1, 1.2,
,,,2,2.1,2.2
3,,,,3,3.1,3.2
您可以使用此 ES6 函数创建您正在寻找的二维数组,然后您可以轻松地将其转换为 CSV:
function pivot(arr) {
var mp = new Map();
function setValue(a, path, val) {
if (Object(val) !== val) { // primitive value
var pathStr = path.join('.');
var i = (mp.has(pathStr) ? mp : mp.set(pathStr, mp.size)).get(pathStr);
a[i] = val;
} else {
for (var key in val) {
setValue(a, key == '0' ? path : path.concat(key), val[key]);
}
}
return a;
}
var result = arr.map( obj => setValue([], [], obj) );
return [[...mp.keys()], ...result];
}
function toCsv(arr) {
return arr.map( row =>
row.map ( val => isNaN(val) ? JSON.stringify(val) : +val ).join(',')
).join('\n');
}
// Sample data
var arr = [
{"name": "1", "children": [{"name": "1.1", "children":"1.2"}]},
{"id": "2", "thing": [{"name": "2.1", "children":"2.2"}]},
{"name": "3", "stuff": [{"name": "3.1", "children":"3.2"}]},
];
// Conversion to 2D array and then to CSV:
console.log(toCsv(pivot(arr)));
.as-console-wrapper { max-height: 100% !important; top: 0; }
有关将二维数组转换为 CSV 的其他方法,请参阅此 Q&A。
这是一个 ES5 提案。
您可以迭代数组并将键收集到散列中 table 并稍后使用间隙存储数据。
var data = [{ name: "1", children: [{ name: "1.1", children: "1.2" }] }, { id: "2", thing: [{ name: "2.1", children: "2.2" }] }, { name: "3", stuff: [{ name: "3.1", children: "3.2" }] }],
csv = function (array) {
var cols = [],
collection = Object.create(null),
i = -1,
toCSV = function (v) { return isNaN(v)? JSON.stringify(v): v; },
csv;
array.forEach(function iter(path) {
return function (o) {
path.length || i++;
Object.keys(o).forEach(function (k) {
if (Array.isArray(o[k])) {
o[k].forEach(iter(path.concat(k)));
return;
}
var key = path.concat(k).join('.');
if (!collection[key]) {
cols.push(key);
collection[key] = [];
}
collection[key][i] = o[k];
});
};
}([]));
csv = cols.map(toCSV).join() + '\n';
for (i = 0; i < array.length; i++) {
csv += cols.map(function (k) { return toCSV(collection[k][i]); }).join() + '\n';
}
return csv;
}(data);
console.log(csv);