JavaScript中使用reduce统计对象数组的用户操作次数问题
问题:使用reduce统计用户各类操作次数失败
首先我有一组社交操作数据:
const tweets = [ {'action': 'tweet', 'user': 'loser', 'message': 'fooboo'}, {'action': 'follow', 'user': 'loser', 'message': null }, {'action': 'tweet', 'user': 'loser', 'message': 'hello'}, {'action': 'retweet', 'user': 'loser', 'message': null}, {'action': 'tweet', 'user': 'michael', 'message': 'CIA is watching'}, {'action': 'tweet', 'user': 'michael', 'message': 'HEHEHEHE'}, {'action': 'follow', 'user': 'michael', 'message': null } ];
我想用reduce方法遍历数组,统计每个用户的各类操作次数,期望输出是:
{ loser: { tweets: 2, retweets: 1, follows: 1 }, michael: { tweets: 2, retweets: 0, follows: 1 } }
但我写的代码无法得到正确结果:
let userCount = tweets.reduce(function(users, line, idx) { users[line['users']] = users[line['user']] || []; let action = line['action']; users[line.user].push({ action: users[line.user].action + 1 || 0 }) return users }, {users: []});
当前错误输出是:
{ michael: [ { action: 1 } ], loser: [ { action: 1 }, { action: 1 }, { action: 1 } ], }
解决方案
咱们一步步来修正你的代码:
1. 修正核心错误点
你的代码里有几个关键问题:
- 拼写错误:
line['users']多了个s,应该是line['user']或者line.user - 初始值错误:初始给的
{users: []}不符合需求,应该用空对象{},方便以用户名作为键存储统计数据 - 用户结构错误:你给每个用户初始化了数组,但我们需要的是包含
tweets/retweets/follows的对象 - 计数逻辑错误:用
push添加对象的方式完全不对,应该直接对对应操作的数值进行累加
2. 正确实现代码
这里提供两种写法,你可以根据习惯选择:
写法一:用switch分支处理操作类型
const tweets = [ {'action': 'tweet', 'user': 'loser', 'message': 'fooboo'}, {'action': 'follow', 'user': 'loser', 'message': null }, {'action': 'tweet', 'user': 'loser', 'message': 'hello'}, {'action': 'retweet', 'user': 'loser', 'message': null}, {'action': 'tweet', 'user': 'michael', 'message': 'CIA is watching'}, {'action': 'tweet', 'user': 'michael', 'message': 'HEHEHEHE'}, {'action': 'follow', 'user': 'michael', 'message': null } ]; const userCount = tweets.reduce((users, line) => { // 初始化用户统计结构:如果用户不存在,就创建一个默认计数全为0的对象 users[line.user] = users[line.user] || { tweets: 0, retweets: 0, follows: 0 }; // 根据操作类型对应累加计数 switch(line.action) { case 'tweet': users[line.user].tweets++; break; case 'retweet': users[line.user].retweets++; break; case 'follow': users[line.user].follows++; break; // 可选:处理未知操作类型 default: console.warn(`未知操作类型:${line.action}`); break; } return users; }, {}); // 初始值设为空对象 console.log(userCount);
写法二:用操作映射简化代码(更简洁)
const tweets = [ {'action': 'tweet', 'user': 'loser', 'message': 'fooboo'}, {'action': 'follow', 'user': 'loser', 'message': null }, {'action': 'tweet', 'user': 'loser', 'message': 'hello'}, {'action': 'retweet', 'user': 'loser', 'message': null}, {'action': 'tweet', 'user': 'michael', 'message': 'CIA is watching'}, {'action': 'tweet', 'user': 'michael', 'message': 'HEHEHEHE'}, {'action': 'follow', 'user': 'michael', 'message': null } ]; // 建立操作名和统计键名的映射关系 const actionToKey = { tweet: 'tweets', retweet: 'retweets', follow: 'follows' }; const userCount = tweets.reduce((users, line) => { users[line.user] = users[line.user] || { tweets: 0, retweets: 0, follows: 0 }; // 找到对应的统计键名,然后累加 const targetKey = actionToKey[line.action]; if (targetKey) { users[line.user][targetKey]++; } return users; }, {}); console.log(userCount);
运行任意一种写法,都能得到你期望的统计结果啦。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

