我已经将基于 CSV 的文本文件转换为包含标题和行的数组,现在我想将它们转换为下面给出的解决方案。任何人都可以使用map
,reduce
或其他方法做到这一点吗?
我拥有的数组是:
let header = ['a', 'b', 'c', 'd'];
let rows = ['1,2,3,4', '5,6,7,8', '9,0,1,2'];
我想要的结果是:
[{
a: 1,
b: 2,
c: 3,
d: 4,
}, {
a: 5,
b: 6,
c: 7,
d: 8,
}, {
a: 9,
b: 0,
c: 1,
d: 2,
}]
我能够使用 for 循环来做到这一点,但这不是 es6 的合适解决方案。
上面我提到了一些虚拟数组,现在实际的代码是:
const recordReader = content => {
let weatherRecords = [];
let rows = content.split('n');
let headers = rows.shift().split(',');
for (let row = 0; row < rows.length; row++) {
let weatherReading = {};
if (!rows[row]) {
continue;
}
let record = rows[row].split(',');
for (let column = 0; column < headers.length; column++) {
weatherReading[headers[column]] = record[column];
}
weatherRecords.push(weatherReading);
}
return weatherRecords;
};
您可以映射行并将行缩减为对象:
const header = ['a', 'b', 'c', 'd'];
const rows = ['1,2,3,4', '5,6,7,8', '9,0,1,2'];
const result = rows.map((row) =>
row.split(',').reduce(
(obj, cell, i) => ({
...obj,
[header[i]]: Number(cell),
}),
{}
)
);
console.log(result)
map和reduce的组合:
const header = ['a', 'b', 'c', 'd'];
const rows = ['1,2,3,4', '5,6,7,8', '9,0,1,2'];
const res = rows.map(row => {
const columns = row.split(',');
return columns.reduce( (acc,cur,i) => ({...acc,[header[i]]:cur}) , {})
}
);
console.log(res);
这承认一行,但我认为不是很清楚它的作用:
const header = ['a', 'b', 'c', 'd'];
const rows = ['1,2,3,4', '5,6,7,8', '9,0,1,2'];
const res = rows.map(row => row.split(',').reduce( (acc,cur,i) => ({...acc,[header[i]]:cur}) , {}));
console.log(res);
您可以将rows
元素.map()
到对象。要创建对象,您可以获取数字字符串,并将它们拆分为一个数组,然后使用.map()
该数组从headers
中获取数字值和关联的标头,使用当前数字的索引 (i
)。通过将它们放入[key, value]
对数组中,您可以在其上调用Object.fromEntries()
来构建对象。下面还使用一元加号运算符 (+
) 将字符串数字转换为数字:
const header = ['a', 'b', 'c', 'd'];
const rows = ['1,2,3,4', '5,6,7,8', '9,0,1,2'];
const res = rows.map(item =>
Object.fromEntries(item.split(',').map((n, i) => [header[i], +n]))
);
console.log(res);
注意,上面用的Object.fromEntries()
是在 ES6 之后引入的,你可以用Object.assign()
来做一个微笑的方法,也就是 ES6:
const header = ['a', 'b', 'c', 'd'];
const rows = ['1,2,3,4', '5,6,7,8', '9,0,1,2'];
const res = rows.map(item =>
Object.assign({}, ...item.split(',').map((n, i) => ({[header[i]]: +n})))
);
console.log(res);
试试这段代码
let header = ['a', 'b', 'c', 'd'];
let rows = ['1,2,3,4', '5,6,7,8', '9,0,1,2'];
let result = rows.map((x) => {
let elementArr = x.split(',');
let response = [];
header.forEach((item,i) => {
response[item] = parseInt(elementArr[i])
});
return {...response};
});
console.log(result)
试试这个
let header = ['a', 'b', 'c', 'd'];
let rows = ['1,2,3,4', '5,6,7,8', '9,0,1,2'];
result=[]
rows.forEach(e=>{
let a={};
let i=0;
header.forEach((h)=>{
a[h]=e.split(',')[i++]
});
result.push(a)
});
基于嵌套reduce
的方法就可以完成这项工作。
一个使用外部化简函数迭代rows
数组,该函数再次通过第二个reduce
任务迭代每个列值(派生自每个split
tedrow
),该任务将列值分配给列键,其中每个键都派生自额外传递的header
数组和当前内部迭代的列索引。
function rowwiseAssignColumValuesToHeaderColumnKeys({ header, result }, row) {
result
.push(
row
.split(',')
.reduce((rowItem, columnValue, columnIndex) =>
Object.assign(rowItem, {
[ header[columnIndex] ]: Number(columnValue.trim())
}), {} // to be aggregated `rowItem` passed as initial value.
)
);
return { header, result };
}
console.log(
['1,2,3,4', '5, 6, 7, 8', '9,0,1,2']
.reduce(
rowwiseAssignColumValuesToHeaderColumnKeys, {
header: ['a', 'b', 'c', 'd'],
result: [],
},
).result
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
上述主要基于reduce
的方法可以重构为可重用的映射函数,该函数考虑了Array.prototype.map
的第二个thisArg
参数
function assignColumValuesAccordingToBoundHeaderColumnKeys(row) {
const header = this;
return row
.split(',')
.reduce((rowItem, columnValue, columnIndex) =>
Object.assign(rowItem, {
[ header[columnIndex] ]: Number(columnValue.trim())
}), {} // to be aggregated `rowItem` passed as initial value.
);
}
console.log(
['1,2,3,4', '5, 6, 7, 8', '9,0,1,2']
.map(
assignColumValuesAccordingToBoundHeaderColumnKeys,
['a', 'b', 'c', 'd'],
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }