如何在 Javascript 中压缩和重新映射数组数据
How to condense and remap data of array in Javascript
我有这个数据数组,需要它的重新映射版本来遍历日期。
var objArr = [
{"Country": "US", "2017-07-12": "1", "2017-07-13": "2"},
{"Country": "US", "2017-07-12": "2", "2017-07-13": "2"},
{"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"},
{"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}
]
- 这些国家应该对它们的值求和,并且不应在内部数组中出现两次。
- 最后我想要一个这样的数组:
var remapped = [
{"2017-07-12": [
{"Country: "US", "value": 3},
{"Country: "CN", "value": 10}],
{"2017-07-13": [
{"Country: "US", "value": 4},
{"Country: "US", "value": 14}]
]
在我目前的情况下,我明白了,但是国家应该减少并且价值相加:
var remapped = [
{"2017-07-12": [
{"Country: "US", "value": 1},
{"Country: "US", "value": 2},
{"Country: "CN", "value": 5}],
{"Country: "CN", "value": 5}
],
{"2017-07-13": [
{"Country: "US", "value": 2},
{"Country: "US", "value": 2},
{"Country: "US", "value": 7}
{"Country: "US", "value": 7}
]
]
这就是我到目前为止的内容。但对我来说,这似乎过于复杂,而且我相信有一种更有效的方法可以解决这个问题:
在这种情况下,我已将国家/地区重新映射到日期中,但不确定如何 "reduce" 它们。我真的必须对数组进行多次迭代吗?
const res = [];
dateArray.forEach(date => (objArr[date] = [])); // I create an array with dates which could contain another array
objArr.forEach(item => {
dates.forEach(date => {
res[date].push({
Country: item['Country'],
value: item[date],
});
});
});
您可以使用 reduce
方法执行此操作,并首先将每个日期的值存储在一个对象中,以便您可以按国家/地区对它们进行分组,然后将这些对象转换为数组。
var data = [
{"Country": "US", "2017-07-12": "1", "2017-07-13": "2"},
{"Country": "US", "2017-07-12": "2", "2017-07-13": "2"},
{"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"},
{"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}
]
const result = data.reduce((r, {Country, ...rest}, i) => {
Object.entries(rest).forEach(([k, v]) => {
if(!r[k]) r[k] = {}
if(!r[k][Country]) r[k][Country] = {Country, value: +v}
else r[k][Country].value += +v
})
return r;
}, {})
for(let i in result) {
result[i] = Object.values(result[i])
}
console.log(result)
您可以为对象的引用获取一个辅助对象,并迭代给定数据的 key/value 对。
var data = [{ Country: "US", "2017-07-12": "1", "2017-07-13": "2" }, { Country: "US", "2017-07-12": "2", "2017-07-13": "2" }, { Country: "CN", "2017-07-12": "5", "2017-07-13": "7" }, { Country: "CN", "2017-07-12": "5", "2017-07-13": "7" }],
reference = {},
result = data.reduce((r, { Country, ...o }) => {
Object.entries(o).forEach(([k, v]) => {
if (!reference[k]) {
reference[k] = { _: [] };
r.push({ [k]: reference[k]._ });
}
if (!reference[k][Country]) {
reference[k]._.push(reference[k][Country] = { Country, value: 0 });
}
reference[k][Country].value += +v;
});
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
这是另一种方法:
const extractDates = objArr => Object .entries (objArr .reduce (
(a, {Country, ...rest}) => Object .entries (rest) .reduce ((a, [date, val]) => ({
...a,
[date]: {...a [date], [Country]: ((a [date] || {}) [Country] || 0) + Number (val)}
}), a),
{}
)) .map (([d, o]) => ({[d]: Object .entries (o) .map (([k, v]) => ({Country: k, value: v}))}))
const objArr = [{"Country": "US", "2017-07-12": "1", "2017-07-13": "2"}, {"Country": "US", "2017-07-12": "2", "2017-07-13": "2"}, {"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}, {"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}]
console .log (extractDates (objArr))
.as-console-wrapper {max-height: 100% !important; top: 0}
这给出了你在问题中要求的结果,一个一键元素数组。但请注意,它是围绕这个核心构建的:
objArr .reduce (
(a, {Country, ... rest}) => Object .entries (rest) .reduce ((a, [date, val]) => ({
...a,
[date]: {... a [date], [Country]: ((a [date] || {}) [Country] || 0) + Number (val)}
}), a),
{}
)
这对我来说是一个更有用的数据结构:
{
"2017-07-12": {CN: 10, US: 3},
"2017-07-13": {CN: 14, US: 4}
}
虽然最终结构(没有 Object .entries (...) .map (...)
包装器)可以在一次通过中构建(例如参见 Nina 的回答;来自 Nenand Vracar 的结构略有不同,但我发现这种分解更清晰,并认为中间格式在大多数情况下更易于使用。
我有这个数据数组,需要它的重新映射版本来遍历日期。
var objArr = [
{"Country": "US", "2017-07-12": "1", "2017-07-13": "2"},
{"Country": "US", "2017-07-12": "2", "2017-07-13": "2"},
{"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"},
{"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}
]
- 这些国家应该对它们的值求和,并且不应在内部数组中出现两次。
- 最后我想要一个这样的数组:
var remapped = [
{"2017-07-12": [
{"Country: "US", "value": 3},
{"Country: "CN", "value": 10}],
{"2017-07-13": [
{"Country: "US", "value": 4},
{"Country: "US", "value": 14}]
]
在我目前的情况下,我明白了,但是国家应该减少并且价值相加:
var remapped = [
{"2017-07-12": [
{"Country: "US", "value": 1},
{"Country: "US", "value": 2},
{"Country: "CN", "value": 5}],
{"Country: "CN", "value": 5}
],
{"2017-07-13": [
{"Country: "US", "value": 2},
{"Country: "US", "value": 2},
{"Country: "US", "value": 7}
{"Country: "US", "value": 7}
]
]
这就是我到目前为止的内容。但对我来说,这似乎过于复杂,而且我相信有一种更有效的方法可以解决这个问题: 在这种情况下,我已将国家/地区重新映射到日期中,但不确定如何 "reduce" 它们。我真的必须对数组进行多次迭代吗?
const res = [];
dateArray.forEach(date => (objArr[date] = [])); // I create an array with dates which could contain another array
objArr.forEach(item => {
dates.forEach(date => {
res[date].push({
Country: item['Country'],
value: item[date],
});
});
});
您可以使用 reduce
方法执行此操作,并首先将每个日期的值存储在一个对象中,以便您可以按国家/地区对它们进行分组,然后将这些对象转换为数组。
var data = [
{"Country": "US", "2017-07-12": "1", "2017-07-13": "2"},
{"Country": "US", "2017-07-12": "2", "2017-07-13": "2"},
{"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"},
{"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}
]
const result = data.reduce((r, {Country, ...rest}, i) => {
Object.entries(rest).forEach(([k, v]) => {
if(!r[k]) r[k] = {}
if(!r[k][Country]) r[k][Country] = {Country, value: +v}
else r[k][Country].value += +v
})
return r;
}, {})
for(let i in result) {
result[i] = Object.values(result[i])
}
console.log(result)
您可以为对象的引用获取一个辅助对象,并迭代给定数据的 key/value 对。
var data = [{ Country: "US", "2017-07-12": "1", "2017-07-13": "2" }, { Country: "US", "2017-07-12": "2", "2017-07-13": "2" }, { Country: "CN", "2017-07-12": "5", "2017-07-13": "7" }, { Country: "CN", "2017-07-12": "5", "2017-07-13": "7" }],
reference = {},
result = data.reduce((r, { Country, ...o }) => {
Object.entries(o).forEach(([k, v]) => {
if (!reference[k]) {
reference[k] = { _: [] };
r.push({ [k]: reference[k]._ });
}
if (!reference[k][Country]) {
reference[k]._.push(reference[k][Country] = { Country, value: 0 });
}
reference[k][Country].value += +v;
});
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
这是另一种方法:
const extractDates = objArr => Object .entries (objArr .reduce (
(a, {Country, ...rest}) => Object .entries (rest) .reduce ((a, [date, val]) => ({
...a,
[date]: {...a [date], [Country]: ((a [date] || {}) [Country] || 0) + Number (val)}
}), a),
{}
)) .map (([d, o]) => ({[d]: Object .entries (o) .map (([k, v]) => ({Country: k, value: v}))}))
const objArr = [{"Country": "US", "2017-07-12": "1", "2017-07-13": "2"}, {"Country": "US", "2017-07-12": "2", "2017-07-13": "2"}, {"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}, {"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}]
console .log (extractDates (objArr))
.as-console-wrapper {max-height: 100% !important; top: 0}
这给出了你在问题中要求的结果,一个一键元素数组。但请注意,它是围绕这个核心构建的:
objArr .reduce (
(a, {Country, ... rest}) => Object .entries (rest) .reduce ((a, [date, val]) => ({
...a,
[date]: {... a [date], [Country]: ((a [date] || {}) [Country] || 0) + Number (val)}
}), a),
{}
)
这对我来说是一个更有用的数据结构:
{
"2017-07-12": {CN: 10, US: 3},
"2017-07-13": {CN: 14, US: 4}
}
虽然最终结构(没有 Object .entries (...) .map (...)
包装器)可以在一次通过中构建(例如参见 Nina 的回答;来自 Nenand Vracar 的结构略有不同,但我发现这种分解更清晰,并认为中间格式在大多数情况下更易于使用。