即使我强烈认为它必须存在,我也很难在其他stackoverflow帖子中找到所需的解决方案。如果有,请按照正确的方向转发我。
我正在尝试使用体育数据在javascript中进行标准分组。我有以下对象数组:
const myData = [
{team: "GSW", pts: 120, ast: 18, reb: 11},
{team: "GSW", pts: 125, ast: 28, reb: 18},
{team: "GSW", pts: 110, ast: 35, reb: 47},
{team: "HOU", pts: 100, ast: 17, reb: 43},
{team: "HOU", pts: 102, ast: 14, reb: 32},
{team: "SAS", pts: 127, ast: 21, reb: 25},
{team: "SAS", pts: 135, ast: 25, reb: 37},
{team: "SAS", pts: 142, ast: 18, reb: 27}
]
我的数据中的每一行都对应于特定篮球比赛的结果。简而言之,我想对数据进行分组,并对分组后的数据应用均值/平均值函数。我期望的结果是:
const groupedData = [
{team: "GSW", pts: 118.3, ast: 27.0, reb: 25.3},
{team: "HOU", pts: 101, ast: 15.5, reb: 37.5},
{team: "SAS", pts: 134.7, ast: 21.3, reb: 29.7}
]
我更喜欢在此处使用带有reduce()的原始javascript ...鉴于我对reduce的了解,这似乎是最好的方法。我目前正在研究此问题,如果有人可以在别人发布答案之前将其投入使用,则会发布。
编辑:我的实际数据有30个键。我希望找到一个解决方案,简单地要求我要么(a)仅指定要分组的“团队”列,然后假设将其余的分组,要么(b)传递一组统计列(点,资产等)。 ),而不是为每个统计信息创建一行。
谢谢!
答案 0 :(得分:5)
一种方法是结合使用reduce
和map
。
const myData = [
{team: "GSW", pts: 120, ast: 18, reb: 11},
{team: "GSW", pts: 125, ast: 28, reb: 18},
{team: "GSW", pts: 110, ast: 35, reb: 47},
{team: "HOU", pts: 100, ast: 17, reb: 43},
{team: "HOU", pts: 102, ast: 14, reb: 32},
{team: "SAS", pts: 127, ast: 21, reb: 25},
{team: "SAS", pts: 135, ast: 25, reb: 37},
{team: "SAS", pts: 142, ast: 18, reb: 27}
]
// Calculate the sums and group data (while tracking count)
const reduced = myData.reduce(function(m, d){
if(!m[d.team]){
m[d.team] = {...d, count: 1};
return m;
}
m[d.team].pts += d.pts;
m[d.team].ast += d.ast;
m[d.team].reb += d.reb;
m[d.team].count += 1;
return m;
},{});
// Create new array from grouped data and compute the average
const result = Object.keys(reduced).map(function(k){
const item = reduced[k];
return {
team: item.team,
ast: item.ast/item.count,
pts: item.pts/item.count,
reb: item.reb/item.count
}
})
console.log(JSON.stringify(result,null,4));
编辑:刚刚看到您对问题的更新。如果可以将白名单(提供要计算的键数组)或黑名单(提供要忽略的键数组)键以编程方式做到这一点,则可以取消每个键的每一行。
const myData = [
{team: "GSW", pts: 120, ast: 18, reb: 11},
{team: "GSW", pts: 125, ast: 28, reb: 18},
{team: "GSW", pts: 110, ast: 35, reb: 47},
{team: "HOU", pts: 100, ast: 17, reb: 43},
{team: "HOU", pts: 102, ast: 14, reb: 32},
{team: "SAS", pts: 127, ast: 21, reb: 25},
{team: "SAS", pts: 135, ast: 25, reb: 37},
{team: "SAS", pts: 142, ast: 18, reb: 27}
]
/**
* Function which accepts a data array and a list of whitelisted
* keys to find the average of each key after grouping
*/
function getGroupedData(data, whitelist) {
// Calculate the sums and group data (while tracking count)
const reduced = data.reduce(function(m, d) {
if (!m[d.team]) {
m[d.team] = { ...d,
count: 1
};
return m;
}
whitelist.forEach(function(key) {
m[d.team][key] += d[key];
});
m[d.team].count += 1;
return m;
}, {});
// Create new array from grouped data and compute the average
return Object.keys(reduced).map(function(k) {
const item = reduced[k];
const itemAverage = whitelist.reduce(function(m, key) {
m[key] = item[key] / item.count;
return m;
}, {})
return {
...item, // Preserve any non white-listed keys
...itemAverage // Add computed averege for whitelisted keys
}
})
}
console.log(JSON.stringify(getGroupedData(myData, ['pts', 'ast', 'reb']), null, 4));
答案 1 :(得分:0)
const myData = [
{team: "GSW", pts: 120, ast: 18, reb: 11},
{team: "GSW", pts: 125, ast: 28, reb: 18},
{team: "GSW", pts: 110, ast: 35, reb: 47},
{team: "HOU", pts: 100, ast: 17, reb: 43},
{team: "HOU", pts: 102, ast: 14, reb: 32},
{team: "SAS", pts: 127, ast: 21, reb: 25},
{team: "SAS", pts: 135, ast: 25, reb: 37},
{team: "SAS", pts: 142, ast: 18, reb: 27}
]
const groubElement = myData.reduce((obj, val) => {
if (obj[val.team]) {
obj[val.team].pts = obj[val.team].pts + val.pts;
obj[val.team].ast = obj[val.team].pts + val.ast;
obj[val.team].reb = obj[val.team].pts + val.reb;
obj[val.team].counter = obj[val.team].counter + 1;
} else {
obj[val.team] = val;
obj[val.team].counter = 1;
}
return obj;
}, {});
const groupElementWithMean = Object.values(groubElement).map(({
counter,
...element
}) => {
element.pts = (element.pts / counter).toFixed(1);
element.ast = (element.ast / counter).toFixed(1);
element.reb = (element.reb / counter).toFixed(1);
return element;
});
console.log(groupElementWithMean);
答案 2 :(得分:0)
您可以通过将reduce
与Object.keys
和Array.prototype.map
结合使用,如下所示:-
const myData = [
{ team: "GSW", pts: 120, ast: 18, reb: 11 },
{ team: "GSW", pts: 125, ast: 28, reb: 18 },
{ team: "GSW", pts: 110, ast: 35, reb: 47 },
{ team: "HOU", pts: 100, ast: 17, reb: 43 },
{ team: "HOU", pts: 102, ast: 14, reb: 32 },
{ team: "SAS", pts: 127, ast: 21, reb: 25 },
{ team: "SAS", pts: 135, ast: 25, reb: 37 },
{ team: "SAS", pts: 142, ast: 18, reb: 27 }
]
let grpData = myData.reduce((acc, cv) => {
if (!acc[cv.team]) {
acc[cv.team] = {};
acc[cv.team].team = cv.team;
acc[cv.team].count = acc[cv.team].pts = acc[cv.team].ast = acc[cv.team].reb = 0
}
acc[cv.team].count++;
acc[cv.team].pts += cv.pts;
acc[cv.team].ast += cv.ast;
acc[cv.team].reb += cv.reb;
return acc;
}, {});
grpData = Object.keys(grpData).map(key => {
let { team, reb, ast, pts, count } = grpData[key];
return {
team, reb: reb / count, ast: ast / count, pts: pts / count
};
})
console.log(grpData);
答案 3 :(得分:0)
您可以使用Map
采取动态方法,并在收集未知密钥后生成所有项目。
function groupBy(array, key) {
return Array.from(
array.reduce((m, o) => {
var temp = m.get(o[key]);
if (!temp) {
m.set(o[key], temp = {});
}
Object.entries(o).forEach(([k, v]) => {
if (k === key) {
return;
}
temp[k] = temp[k] || { sum: 0, count: 0 };
temp[k].sum += v;
temp[k].count++;
});
return m;
}, new Map),
([k, v]) => Object.assign({ [key]: k }, ...Object.entries(v).map(([l, { sum, count }]) => ({ [l]: +(sum / count).toFixed(1) })))
);
}
const myData = [{ team: "GSW", pts: 120, ast: 18, reb: 11 }, { team: "GSW", pts: 125, ast: 28, reb: 18 }, { team: "GSW", pts: 110, ast: 35, reb: 47 }, { team: "HOU", pts: 100, ast: 17, reb: 43 }, { team: "HOU", pts: 102, ast: 14, reb: 32 }, { team: "SAS", pts: 127, ast: 21, reb: 25 }, { team: "SAS", pts: 135, ast: 25, reb: 37 }, { team: "SAS", pts: 142, ast: 18, reb: 27 }];
console.log(groupBy(myData, 'team'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
具有休息属性(babel: true
)。
function groupBy(array, key) {
return Array.from(
array.reduce((m, { [key]: k, ...rest}) => {
var temp = m.get(k);
if (!temp) {
m.set(k, temp = {});
}
Object.entries(rest).forEach(([l, v]) => {
temp[l] = temp[l] || { sum: 0, count: 0 };
temp[l].sum += v;
temp[l].count++;
});
return m;
}, new Map),
([k, v]) => Object.assign({ [key]: k }, ...Object.entries(v).map(([l, { sum, count }]) => ({ [l]: +(sum / count).toFixed(1) })))
);
}
const myData = [{ team: "GSW", pts: 120, ast: 18, reb: 11 }, { team: "GSW", pts: 125, ast: 28, reb: 18 }, { team: "GSW", pts: 110, ast: 35, reb: 47 }, { team: "HOU", pts: 100, ast: 17, reb: 43 }, { team: "HOU", pts: 102, ast: 14, reb: 32 }, { team: "SAS", pts: 127, ast: 21, reb: 25 }, { team: "SAS", pts: 135, ast: 25, reb: 37 }, { team: "SAS", pts: 142, ast: 18, reb: 27 }];
console.log(groupBy(myData, 'team'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 4 :(得分:0)
使用statsFields
数组并循环遍历以创建总计,然后获取平均值
const myData = [
{team: "GSW", pts: 120, ast: 18, reb: 11},
{team: "GSW", pts: 125, ast: 28, reb: 18},
{team: "GSW", pts: 110, ast: 35, reb: 47},
{team: "HOU", pts: 100, ast: 17, reb: 43},
{team: "HOU", pts: 102, ast: 14, reb: 32},
{team: "SAS", pts: 127, ast: 21, reb: 25},
{team: "SAS", pts: 135, ast: 25, reb: 37},
{team: "SAS", pts: 142, ast: 18, reb: 27}
]
const statsFields = ['pts','ast','reb'];
const teamsObject = myData.reduce((a,{team,...stats})=>{
a[team] = a[team] || {team, games:0};
a[team].games++
statsFields.forEach(k=> a[team][k] = (a[team][k] || 0) + stats[k]);
return a;
},{});
const res = Object.values(teamsObject).map(({games,...team})=>{
// average for each field total/games
statsFields.forEach(k=> team[k] = team[k]/games);
return team;
})
console.log(JSON.stringify(res))
答案 5 :(得分:0)
可以很简单地完成以下操作。
注意:使用JSON.parse和stringify深浅复制数据。否则原始数组将被修改。如果可以修改原始数组,则不需要它。
const data = [
{team: "GSW", pts: 120, ast: 18, reb: 11},
{team: "GSW", pts: 125, ast: 28, reb: 18},
{team: "GSW", pts: 110, ast: 35, reb: 47},
{team: "HOU", pts: 100, ast: 17, reb: 43},
{team: "HOU", pts: 102, ast: 14, reb: 32},
{team: "SAS", pts: 127, ast: 21, reb: 25},
{team: "SAS", pts: 135, ast: 25, reb: 37},
{team: "SAS", pts: 142, ast: 18, reb: 27}
];
function groupData(mydata,keys)
{
var accresult = mydata.reduce(function(acc, value){
var arr = acc.filter(function(obj){return obj.team==value.team});
arr.length ? (item=arr[0] , keys.forEach(function(key){ item[key]+=value[key]; })) : acc.push(value);
return acc;
},[]);
var result = accresult.map(function(val){
var l = mydata.filter(function(obj){return obj.team==val.team}).length;
keys.forEach(function(key){ val[key]=(val[key]/l).toFixed(2); })
return val;
});
return result;
}
console.log(groupData(JSON.parse(JSON.stringify(data.slice(0))),['pts','ast']));
console.log(groupData(JSON.parse(JSON.stringify(data.slice(0))),['pts','ast','reb']));
console.log(groupData(JSON.parse(JSON.stringify(data.slice(0))),['pts']));
答案 6 :(得分:0)
const myData = [
{ team: "GSW", pts: 120 },
{ team: "HOU", pts: 100 },
{ team: "GSW", pts: 110 },
{ team: "SAS", pts: 135 },
{ team: "HOU", pts: 102 },
{ team: "SAS", pts: 127 },
{ team: "SAS", pts: 142 },
{ team: "GSW", pts: 125 }
];
var result = myData.reduce(function (a, b) {
var exist = -1;
//some breaks the loop once it gets the true
a.some((x, y) => {
if (x.team == b.team) {
//assigning index of existing object in array
exist = y;
return true;
} else {
return false;
}
});
if (exist == -1) {
a.push({ team: b.team, pts: b.pts, count: 1 });
} else {
a[exist].count += 1;
a[exist].pts += b.pts;
}
return a;
}, []).map(t => {return {team: t.team, avg: t.pts/t.count, count:t.count}});
console.log(result);