【问题标题】:Sum of Parts of An Array - JavaScript数组部分的总和 - JavaScript
【发布时间】:2019-11-06 10:04:45
【问题描述】:

试图解决this challenge on codewars。根据挑战,数组的部分:

ls = [0, 1, 3, 6, 10]

ls = [0, 1, 3, 6, 10]
ls = [1, 3, 6, 10]
ls = [3, 6, 10]
ls = [6, 10]
ls = [10]
ls = []

我们需要返回一个包含这些部分总和的数组。

所以我的代码如下:

function partsSums(ls) {
  let arrayOfSums = []; 
  while(ls.length > 0) {
    let sum = ls.reduce((a, b) => a + b);
    arrayOfSums.push(sum);
    ls.shift();
  }
return arrayOfSums;
}

console.log(partsSums([0, 1, 3, 6, 10]));

问题是它希望我们在数组为空时添加最后一个总和 0。所以我们应该得到:

[ 20, 20, 19, 16, 10, 0 ]

代替

[20、20、19、16、10]

所以我尝试了这个:

function partsSums(ls) {
  let arrayOfSums = []; 
  while(ls.length > 0) {
    let sum = ls.reduce((a, b) => a + b);
    arrayOfSums.push(sum);
    ls.shift();
  }
arrayOfSums.push(0);
return arrayOfSums;
}
console.log(partsSums([0, 1, 3, 6, 10]));

还有这个:

function partsSums(ls) {
  ls.push(0);
  let arrayOfSums = []; 
  while(ls.length > 0) {
    let sum = ls.reduce((a, b) => a + b);
    arrayOfSums.push(sum);
    ls.shift();
  }
return arrayOfSums;
}

但是这些导致 Codewars 上的执行超时错误:

执行超时(12000 毫秒)

所以我也试过了:

function partsSums(ls) {
  let arrayOfSums = []; 
  while(ls.length > -1) {
    let sum = ls.reduce((a, b) => a + b);
    arrayOfSums.push(sum);
    ls.shift();
  }
return arrayOfSums;
}

但现在这会导致 TypeError:

TypeError: 减少没有初始值的空数组

当所有值都移出时,我不理解如何将 0 放入数组的概念。挑战似乎希望 0 作为数组的最终“总和”,即使数组为空。但是你不能减少一个空数组——我还能在这里做什么?

编辑:尝试向 reduce 方法添加初始值:

function partsSums(ls) {
  let arrayOfSums = []; 
  while(ls.length > 0) {
    let sum = ls.reduce((a, b) => a + b, 0);
    arrayOfSums.push(sum);
    ls.shift();
  }
return arrayOfSums;
}

不幸的是,这仍然未能通过基本测试:

预期 [] 深度等于 [0]

【问题讨论】:

  • 我已经尝试自己解决了。我不知道还能尝试什么。我不理解如何将空数组的总和添加到最终数组的概念。因为您不能在空数组上使用 reduce。还有其他想法吗?
  • 你不能在循环后按 0 吗?
  • 这个:但你不能减少一个空数组 - 那不是那个错误消息(TypeError:减少没有初始值的空数组 ) 说。其实很具体:请重新阅读reduce的文档:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - 然后重新阅读错误信息。
  • @RandyCasburn “如果没有提供初始值,将使用数组中的第一个元素。在没有初始值的空数组上调用 reduce() 将引发类型错误。”所以也许 reduce 并不是求数组总和的最佳方法。
  • 宾果游戏!但也要考虑迭代器点。

标签: javascript arrays sum reduce


【解决方案1】:

您可以将for 循环与slice 一起使用,当i == 0 时,您可以对len + 1 进行切片,这将返回空数组并且总和将为0。

function partsSums(arr) {
  const res = [], len = arr.length
  for (let i = len; i > -1; i--) {
    res.push(arr.slice(-i || len + 1).reduce((a, n) => a + n, 0))
  }
  return res;
}

console.log(partsSums([0, 1, 3, 6, 10]));
console.log(partsSums([1, 2, 3, 4, 5, 6]));
console.log(partsSums([744125, 935, 407, 454, 430, 90, 144, 6710213, 889, 810, 2579358]));

你也可以使用两个双精度reduce,如果没有下一个元素则推零。

function partsSums(arr) {
  const sum = arr => arr.reduce((r, e) => r + e, 0);
  return arr.reduce((r, e, i, a) => {
    const res = sum(a.slice(i, a.length));
    return r.concat(!a[i + 1] ? [res, 0] : res)
  }, [])
}

console.log(partsSums([0, 1, 3, 6, 10]));
console.log(partsSums([1, 2, 3, 4, 5, 6]));
console.log(partsSums([744125, 935, 407, 454, 430, 90, 144, 6710213, 889, 810, 2579358]));

【讨论】:

    【解决方案2】:

    没有理由一遍又一遍地计算总和。在长数组上,这将非常低效( O(n²) )并且可能会解释您的超时错误。在开始时计算总和,然后在循环中从中减去每个元素。

    ls = [0, 1, 3, 6, 10]
    
    function partsSums(ls) {
        let sum = ls.reduce((sum, n) => sum + n, 0)
        res  = [sum]
        for (let i = 1; i <= ls.length; i++){
            sum -= ls[i-1]
            res.push(sum )
        }
        return res
    }
    console.log(partsSums(ls))

    【讨论】:

    • O(n²) 意味着所需的计算次数随着数组长度的增长呈指数增长。 reduce 需要查看数组中的每个元素,而您 for 需要查看数组中的每个元素。
    • @NinaScholz 你说的是最初的reduce()吗?至少在 chrome 上,初始总和的开销远小于我测试中unshift() 的惩罚。
    • 因此,为了进一步分解,我们将第一个总和设为20,然后在 for 循环中,我们创建“结果”数组,将其初始化为 20。然后我们从总和中减去ls[i - 1]。因此,从 for 循环推入结果数组的第一个总和也将是 20,因为在这种情况下 ls[i - 1]0。然后是 20 - 1,然后是 19 - 3,等等。有道理 - 谢谢。
    • @HappyHands31 根据 Mark Meyer 的上述评论,如果您需要询问“( O(n^2)) 是什么”,那么您可能会受益于被明确告知这称为 "Big-O" notation.
    【解决方案3】:

    您可以从末尾进行迭代,并获取该值加上结果集中最后插入的值。

    此方法适用于单个循环,无需预先计算最大总和。

    function partsSums(ls) {
      var result = [0],
          i = ls.length;
          
      while (i--) {
          result.unshift(ls[i] + result[0]);
      }
      return result;
    }
    
    console.log(partsSums([0, 1, 3, 6, 10]));
    console.log(partsSums([]));
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    使用pushreverse

    function partsSums(ls) {
      var result = [0],
          l = 0,
          i = ls.length;
          
      while (i--) result.push(l += ls[i]);
      return result.reverse();
    }
    
    console.log(partsSums([0, 1, 3, 6, 10]));
    console.log(partsSums([]));
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

      【解决方案4】:

      用递归试试这个:

      function partsSums(ls) {
        let sum = ls.reduce((a, b) => a + b, 0);
        return  ls.length > 0 ? [sum].concat(partsSums(ls.slice(1))) : [0];
      }
      
      console.log(partsSums([0, 1, 3, 6, 10]));
      console.log(partsSums([1, 2, 3, 4, 5, 6]));
      console.log(partsSums([744125, 935, 407, 454, 430, 90, 144, 6710213, 889, 810, 2579358]));

      【讨论】:

        【解决方案5】:

        这是你可以做的一件事

        function partsSums(ls) {
          if(!ls.length) return [0];
          let prevTotal = ls.reduce((a,b) => a + b);
          return [prevTotal, ...ls.map(val => prevTotal -= val)]
        }
        
        console.log(partsSums([0, 1, 3, 6, 10]));

        【讨论】:

        • 我也喜欢这个 - 你能帮我理解if(!ls.length) return [0] 是如何添加到返回数组的末尾的吗?没有任何循环可以减少ls 的长度?
        • if(!ls.length) return [0] 仅在传入参数的数组为空时使用。它最后返回 0 的原因是因为它总是将值减去总数,所以当你得到最后一个值 (10) 时,你再减去它 (10 - 10) 所以它返回 0!有关map 方法的更多信息,您可以查看here
        【解决方案6】:

        另一个通过所有测试的解决方案:

        function partsSums(ls) {
            let result = [0],
              l = ls.length - 1;
              
            for (let i = l; i >= 0; i--) {
                result.push(ls[i] + result[ l - i]);
            }
            return result.reverse();
        }
        
        
        console.log(partsSums([]));
        console.log(partsSums([0, 1, 3, 6, 10])); 
        console.log(partsSums([1, 2, 3, 4, 5, 6]));
        console.log(partsSums([744125, 935, 407, 454, 430, 90, 144, 6710213, 889, 810, 2579358]));

        【讨论】:

        • 您也可以使用result.unshift(ls[i] + result[0]) 并避免使用reverse
        • @georg unshift 没有通过测试,因为它比 push+reverse
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-10
        • 1970-01-01
        相关资源
        最近更新 更多