在 javascript 中使用 .reduce 从每个特定用户的对象数组中获取总价

get total price from array of objects per specific user using .reduce in javascript

我有这个对象数组

const items = [
  {
    id: '121',
    itemDate: '2022-04-28',
    itemName: 'testname1',
    itemCategory: 'Category A',
    itemPrice: { price: '100', currency: 'GBP' },
    createdBy: {
      username: 'user1',
      name: 'Name 1',
      date: '2022-04-28T22:41:59',
    },
  },
  {
    id: '122',
    itemDate: '2022-04-28',
    itemName: 'testname2',
    itemCategory: 'Category B',
    itemPrice: { price: '100', currency: 'GBP' },
    createdBy: {
      username: 'user2',
      name: 'Name 2',
      date: '2022-04-28T22:42:44',
    },
  },
  {
    id: '122',
    itemDate: '2022-04-28',
    itemName: 'testname3',
    itemCategory: 'Category C',
    itemPrice: { price: '200', currency: 'GBP' },
    createdBy: {
      username: 'user2',
      name: 'Name 2',
      date: '2022-04-28T22:43:16',
    },
  },
]

我使用的代码:

items.reduce(function (c, x) {
  if (!c[x.createdBy.username])
    c[x.createdBy.username] = {
      username: x.createdBy.username,
      total: 0,
    }
  c[x.createdBy.username].total += Number(x.itemPrice.price)
  return c
}, [])

这部分给出了以下输出:

items :>>  [
  user1: { username: 'user1', total: 100},
  user2: { username: 'user2', total: 300}
]

所以我尝试这样做来摆脱对象名称:

let output = []
let totalSum = 0

for (const username in items) {
  let temp = {
    username: items[username].username,
    total: items[username].total,
  }
  totalSum = totalSum + items[username].total
  output.push(temp)
}
output.push({ username: 'allUsers', total: totalSum })

return output

最终输出是我现在想要的:

output :>>  [
  { username: 'user1', total: 100 },
  { username: 'user2', total: 300 },
  { username: 'allUsers', total: 400}
]

我的两个问题...

有没有办法更新 .reduce 部分,这样我就可以得到一个在开始时没有名称的对象,而不必使用 for 循环?

是否还有一种方法可以实现对所有总数求和的部分?

谢谢

对于你的第一个问题,你正确地初始化为一个数组,但你只使用了对象。有两种方法可以做到这一点。

第一个选项

let something = items.reduce(function(c, x) {
  if (!c[x.createdBy.username])
    c[x.createdBy.username] = {
      username: x.createdBy.username,
      total: 0,
    }
  c[x.createdBy.username].total += Number(x.itemPrice.price)
  return c
}, {});
something = Object.values(something);

第二个选项

本来想用push,但是好像不行,所以只有上面的选项了。

可以使用推送,但通过检查查找和更新正确的数组元素会变得太复杂。


对于你的第二个求和所有总数的问题,你可以使用简单的语法:

const sum = arr.reduce((a, c) => a + c, 0);

这是求和数字数组所需的最少代码。

代码示例(没有comments/description)

const groupAndAdd = arr => (
  Object.values(
    arr.reduce(
      (acc, {createdBy : {username}, itemPrice: {price}}) => {
        acc.allUsers ??= { username: 'allUsers', total: 0};
        acc.allUsers.total += +price;
        if (username in acc) {
          acc[username].total += +price;
        } else {
          acc[username] = {username, total: +price};
        }
        return acc;
      },
      {}
    )
  )
);

下面展示的是实现所需 objective 的工作演示,notes/comments 有助于理解。

代码段

// method to group by user and sum prices
const groupAndAdd = arr => (
  // extract the values from the intermediate result-object
  Object.values(
    arr.reduce(             // generate result as object
      (acc, {createdBy : {username}, itemPrice: {price}}) => {
        // above line uses de-structuring to directly access username, price
        // below uses logical nullish assignment to set-up "allUsers"
        acc.allUsers ??= { username: 'allUsers', total: 0};
        
        // accumulate the "price" to the all-users "total"
        acc.allUsers.total += +price;
        
        // if "acc" (accumulator) has "username", simply add price to total
        if (username in acc) {
          acc[username].total += +price;
        } else {
          // create an object for the "username" with initial total as "price"
          acc[username] = {username, total: +price};
        }
        
        // always return the "acc" accumulator for ".reduce()"
        return acc;
      },
      {}                // initially set the "acc" to empty object
    )
  )          // if required, use ".sort()" to move the all-users to last position in array
);

const items = [{
    id: '121',
    itemDate: '2022-04-28',
    itemName: 'testname1',
    itemCategory: 'Category A',
    itemPrice: {
      price: '100',
      currency: 'GBP'
    },
    createdBy: {
      username: 'user1',
      name: 'Name 1',
      date: '2022-04-28T22:41:59',
    },
  },
  {
    id: '122',
    itemDate: '2022-04-28',
    itemName: 'testname2',
    itemCategory: 'Category B',
    itemPrice: {
      price: '100',
      currency: 'GBP'
    },
    createdBy: {
      username: 'user2',
      name: 'Name 2',
      date: '2022-04-28T22:42:44',
    },
  },
  {
    id: '122',
    itemDate: '2022-04-28',
    itemName: 'testname3',
    itemCategory: 'Category C',
    itemPrice: {
      price: '200',
      currency: 'GBP'
    },
    createdBy: {
      username: 'user2',
      name: 'Name 2',
      date: '2022-04-28T22:43:16',
    },
  },
];

console.log('group and add prices per user: ', groupAndAdd(items));
.as-console-wrapper { max-height: 100% !important; top: 0 }

说明

在上面的代码片段中添加了内嵌评论。

PS:如果您想为 Whosebug 社区增加价值,

请考虑阅读:What to do when my question is answered 谢谢!