简体   繁体   English

递归 - 对嵌套数组求和

[英]Recursion - Sum Nested Array

I'm trying to sum a nested array [1,2,[3,4],[],[5]] without using loops but I don't see what's wrong with what I have so far.我试图在不使用循环的情况下对嵌套数组[1,2,[3,4],[],[5]]求和[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;
}

try with尝试

 function sumItems(array) {

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

recursion is a functional heritage递归是一种功能遗产

Recursion is a concept that comes from functional style.递归是一个来自函数式风格的概念。 Mixing it with imperative style is a source of much pain and confusion for new programmers.将它与命令式风格混合在一起会给新程序员带来很多痛苦和困惑。

To design a recursive function , we identify the base and inductive case(s).为了设计递归函数,我们确定基本情况和归纳情况。

  • base case - the list of items to sum is empty;基本情况 - 要求和的项目列表为空; ie, item is Empty .即, itemEmpty return 0返回0
  • inductive case 1 - the list of items is not empty;归纳案例 1 - 项目列表不为空; ie, there must be at least one item .即,必须至少有item if the item is a list, return its sum plus the sum of the rest of the items如果项目是列表,则返回其总和加上rest项目的总和
  • inductive case 2 - there is at least one item that is not an array.归纳案例 2 - 至少有item不是数组。 return this item plus the sum of the rest of the items返回此项目加上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 )

As a result of this implementation, all pain and suffering are removed from the program.作为这种实施的结果,所有的痛苦和痛苦都从程序中消除了。 We do not concern ourselves with local state variables, variable reassignment, or side effects like forEach and not using the return value of a function call.我们不关心局部状态变量、变量重新分配或副作用,如forEach和不使用函数调用的返回值。


recursion caution递归注意

And a tail-recursive version which can be made stack-safe .还有一个可以使堆栈安全的尾递归版本。 Here, we add a parameter cont to represent our continuation which effectively allows us sequence the order of + operations without growing the stack – changes in bold在这里,我们添加了一个参数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))

Usage is identitcal用法相同

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

performance enhancement性能提升

As @גלעד ברקן points out, array destructuring syntax used above (eg ...rest ) create copies of the input array.正如@גלעד ברקן 指出的那样,上面使用的数组解构语法(例如...rest )会创建输入数组的副本。 As demonstrated in his/her answer, an index parameter can be used which will avoid creating copies.如他/她的回答所示,可以使用索引参数来避免创建副本。 This variation shows how the index technique can also be used in a tail-recursive way此变体显示了索引技术也可以以尾递归方式使用

 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 )

Here's a version without using loops:这是一个不使用循环的版本:

 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));

You could define a callback for using with Array#reduce , which check if an item is an array and uses this function again for that array.您可以定义一个用于与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));

You may do as follows;您可以按照以下方式进行;

 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,[]]));

The function argument designation [a,…as] means that when the function is fed with a nested array like [1,2,3,[4,[5,[6]]],7,[]] then a is assigned to the head which is 1 and as is assigned to the tail of the initial array which is [2,3,[4,[5,[6]]],7,[]] .函数参数指定[a,…as]意味着当函数被提供一个像[1,2,3,[4,[5,[6]]],7,[]]这样a嵌套数组时[1,2,3,[4,[5,[6]]],7,[]] a被赋值到头部是1as分配给初始阵列的尾部,其是[2,3,[4,[5,[6]]],7,[]] The rest should be easy to understand.其余的应该很容易理解。

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

This is similar to some of the other solutions but might be easier for some to read:这类似于其他一些解决方案,但对于某些人来说可能更容易阅读:

 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM