递归 - 求和嵌套数组

时间:2018-02-14 16:10:41

标签: javascript recursion

我试图在不使用循环的情况下对嵌套数组[1,2,[3,4],[],[5]]进行求和,但我不知道到目前为止我有什么错误。

function sumItems(array) {

  let sum = 0;
  array.forEach((item) => {
    if(Array.isArray(item)) {
      sumItems(item);
    } else {
    sum += item;
    }
  })
  return sum;
}

7 个答案:

答案 0 :(得分:3)

尝试

fetch

答案 1 :(得分:3)

递归是一种功能性传承

递归是一种来自功能风格的概念。将它与命令式风格混合是新程序员的痛苦和困惑的源泉。

To design a recursive function,我们确定了基础归纳案例。

  • 基础案例 - 要求的项目列表为空;即,itemEmpty。返回0
  • 归纳案例1 - 项目列表为空;即,必须至少有一个item。如果该项目是列表,则返回其总和加上项目的rest的总和
  • 归纳案例2 - 至少有一个item 一个数组。返回此商品加上商品rest的总和

const Empty =
  Symbol ()

const sumDeep = ([ item = Empty, ...rest ] = []) =>
  item === Empty
    ? 0
    : Array.isArray (item)
      ? sumDeep (item) + sumDeep (rest)
      : item + sumDeep (rest)

console.log
  ( sumDeep ([ [ 1, 2 ], [ 3, 4 ], [ 5, [ 6, [] ] ] ]) // 21
  , sumDeep ([ 1, 2, 3, 4, 5, 6 ])                     // 21
  , sumDeep ([])                                       // 0
  , sumDeep ()                                         // 0
  )

由于这种实施,所有的痛苦都会从计划中消除。我们不关心本地状态变量,变量重新分配或副作用,如forEach,也不使用函数调用的返回值。

递归警告

可以制作stack-safe的尾递归版本。在这里,我们添加一个参数cont来表示我们的延续,这有效地允许我们按顺序排列+操作而不增加堆栈 - 粗体

的更改
const identity = x =>
  x

const sumDeep = ([ item = Empty, ...rest ] = [], cont = identity) =>
  item === Empty
    ? cont (0)
    : Array.isArray (item)
      ? sumDeep (item, a =>
         sumDeep (rest, b =>
           cont (a + b)))
      : sumDeep (rest, a =>
          cont (item + a))

用法是标识

console.log
  ( sumDeep ([ [ 1, 2 ], [ 3, 4 ], [ 5, [ 6, [] ] ] ]) // 21
  , sumDeep ([ 1, 2, 3, 4, 5, 6 ])                     // 21
  , sumDeep ([])                                       // 0
  , sumDeep ()                                         // 0
  )

效果提升

正如@גלעדברקן所指出的,上面使用的数组解构语法(例如...rest)创建了输入数组的副本。如他/她的回答所示,可以使用索引参数,这将避免创建副本。此变体显示了索引技术如何也可以以尾递归的方式使用

const identity = x =>
  x

const sumDeep = (items = [], i = 0, cont = identity) =>
  i >= items.length
    ? cont (0)
    : Array.isArray (items [i])
      ? sumDeep (items [i], 0, a =>
          sumDeep (items, i + 1, b =>
            cont (a + b)))
      : sumDeep (items, i + 1, a => 
          cont (items [i] + a))

console.log
  ( sumDeep ([ [ 1, 2 ], [ 3, 4 ], [ 5, [ 6, [] ] ] ]) // 21
  , sumDeep ([ 1, 2, 3, 4, 5, 6 ])                     // 21
  , sumDeep ([])                                       // 0
  , sumDeep ()                                         // 0
  )

答案 2 :(得分:1)

这是一个不使用循环的版本:



function f(arr, i){
  if (i == arr.length)
    return 0;
	
  if (Array.isArray(arr[i]))
    return f(arr[i], 0) + f(arr, i + 1);
	  
  return arr[i] + f(arr, i + 1);
}

console.log(f([1,2,[3,4],[],[5]], 0));




答案 3 :(得分:0)

您可以定义一个与Array#reduce一起使用的回调,它会检查一个项目是否为数组并再次对该数组使用此函数。



function add(s, v) {
    return Array.isArray(v)
        ? v.reduce(add, s)
        : s + v;
}

var array = [1, 2, [3, 4], [], [5]];

console.log(array.reduce(add, 0));




答案 4 :(得分:0)

您可以执行以下操作;

===

函数参数名称var sumNested = ([a,...as]) => (as.length && sumNested(as)) + (Array.isArray(a) ? sumNested(a) : a || 0); console.log(sumNested([1,2,3,[4,[5,[6]]],7,[]]));表示,当函数使用[a,…as]之类的嵌套数组进行填充时,会将[1,2,3,[4,[5,[6]]],7,[]]分配给a和{{ 1}}被分配给初始数组1的尾部。其余的应该很容易理解。

答案 5 :(得分:0)

function arraySum (array) {
  if (array.length > 0) {
    return arraySum(array[0]) + arraySum(array.slice(1));
  }
  if (array.length === 0) {
    return 0;
  } else {
    return array;
  }
};

答案 6 :(得分:0)

这与其他一些解决方案相似,但对于某些人来说可能更容易阅读:

 function Sum(arr) {
   if (!arr.length) return 0;
   if (Array.isArray(arr[0])) return Sum(arr[0]) + Sum(arr.slice(1));
   return arr[0] + Sum(arr.slice(1));
 }

 console.log(Sum([[1],2,[3,[4,[5,[6,[7,[8,9,10],11,[12]]]]]]])) // 78