【问题标题】:In array of objects sum up certain property values if another property has given value如果另一个属性具有给定值,则在对象数组中总结某些属性值
【发布时间】:2020-08-28 21:07:44
【问题描述】:

如果帐户类型为“储蓄”,我将尝试获取帐户余额的总和。我的想法是使用 forEach 循环遍历数组,然后如果帐户类型是储蓄,但不确定为什么它不起作用。

const accounts = [
    {acctNo: 123, type: 'Checking', balance: 150},
    {acctNo: 234, type: 'Checking', balance: 200},
    {acctNo: 345, type: 'Savings', balance: 550},
    {acctNo: 456, type: 'Checking', balance: 550},
    {acctNo: 567, type: 'Savings', balance: 1500}
];
const sum = accounts.forEach(function(account){
  if (account.type=== 'Savings'){
    account.reduce(function(a,b){
      return {balance: a.balance + b.balance}
    })
  }
})

console.log(sum)

【问题讨论】:

  • 你的代码有很多问题——但最根本的是,你把它复杂化了。您只需要将filter 输入到帐户类型为Savingsmap 的帐户中,然后才执行总和(使用reduce 或使用forEach 的总和,无论您喜欢哪个)。

标签: javascript arrays iterator


【解决方案1】:

您不能在 forEach 中返回任何内容,并且直接减少帐户是没有意义的。尝试使用 filter 和 map 代替,并确保在列表上进行 reduce:

accounts.filter(a => a.type === 'Savings')
    .map(a => a.balance)
    .reduce((a, b) => a + b)

【讨论】:

【解决方案2】:

通过链接一些简单的数组方法,您可以做到这一点:

1) 使用filter 仅获取类型为'Savings' 的帐户

2) 使用map 仅获取余额

3) 然后对数组求和,我使用reduce 完成了它,它与mapfilter 很好地放在一起,但是如果你可以使用显式循环并手动跟踪总和,则可以这样做你喜欢

请注意,我使用了箭头函数,只是因为它更简洁,并且更清楚 (imo) 函数在做什么 - 但每个函数都可以用旧式 function() { ... } 表达式替换,它仍然会工作相同。

const accounts = [
    {acctNo: 123, type: 'Checking', balance: 150},
    {acctNo: 234, type: 'Checking', balance: 200},
    {acctNo: 345, type: 'Savings', balance: 550},
    {acctNo: 456, type: 'Checking', balance: 550},
    {acctNo: 567, type: 'Savings', balance: 1500}
];

const sum = accounts.filter(account => account.type === 'Savings')
                    .map(account => account.balance)
                    .reduce((acc, bal) => acc + bal);

console.log(sum)

【讨论】:

  • 你为什么不干脆这样做in 1 pass
  • 公平点-您的答案很简洁,可能性能更高(尽管我不敢说如果没有大型数据集的实际基准,现代 JS 引擎能够进行优化,我什至不会开始理解),但大多数情况下这并不重要。我只是想向 OP 演示一种简单的方法,因为他们显然对各种数组方法的情况感到困惑,所以我发现我的回答所显示的“逐步”思维很有帮助.
  • '...可能性能更高'will see 1k 随机记录的性能提升大约 40%。
  • 公平点(我只是捏造,因为我不确定并且懒得对自己进行基准测试:)) - 但是,当“糟糕”性能版本可以处理 1k 记录数组时1/3000 秒,在你有数十万之前,这不会是一个真正明显的性能差异。你提出这个问题是对的,我感谢你这样做 - 但对于大多数实际用途来说,这无关紧要。
  • Zygmond :我最初评论的重点并不是要强调性能差距,尽管对于某些可能会进行多次繁重计算的应用程序,即使在渲染阶段获得几毫秒的时间也可能很重要。但是,我更愿意展示以真正 懒惰 的方式解决问题的方法;)
【解决方案3】:

reduce 是数组方法,不是对象方法。

您不需要同时使用forEachreducereduce 已经遍历了数组,你只需要将if 条件放入函数中。

const accounts = [
    {acctNo: 123, type: 'Checking', balance: 150},
    {acctNo: 234, type: 'Checking', balance: 200},
    {acctNo: 345, type: 'Savings', balance: 550},
    {acctNo: 456, type: 'Checking', balance: 550},
    {acctNo: 567, type: 'Savings', balance: 1500}
];
const sum = accounts.reduce(function(a, account){
  if (account.type === 'Savings'){
    return a + account.balance;
  } else {
    return a;
  }
}, 0)

console.log(sum)

【讨论】:

    【解决方案4】:

    关注@RobinZigmond 的评论

    filter => 从数组中删除所有非“储蓄”类型的帐户,并将type === 'savings' 的帐户作为数组返回。 map 方法接收这个数组

    map => 返回一个仅包含储蓄账户余额的数组。 reduce收到了

    reduce => 基本上将数组中的所有内容简化为一件事。在这种情况下,它接收余额数组并将它们全部加起来并返回给sum

    const accounts = [
      { acctNo: 123, type: 'Checking', balance: 150 },
      { acctNo: 234, type: 'Checking', balance: 200 },
      { acctNo: 345, type: 'Savings', balance: 550 },
      { acctNo: 456, type: 'Checking', balance: 550 },
      { acctNo: 567, type: 'Savings', balance: 1500 }
    ];
    
    const sum = accounts
      .filter((account) => account.type.toLowerCase() === 'savings')
      .map((savingsAccounts) => savingsAccounts.balance)
      .reduce((accumulator, balance) => accumulator + balance);
    
    console.log(sum);
    

    【讨论】:

    • 对源数组及其过滤副本进行 3 次传递是没有意义的,而 1 是 absolutely enough
    猜你喜欢
    • 2022-11-21
    • 2017-07-24
    • 2019-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-18
    相关资源
    最近更新 更多