Recursion - Sum Nested Array

前端 未结 7 1550
一向
一向 2021-01-03 12:24

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.

function sumItem         


        
相关标签:
7条回答
  • 2021-01-03 13:26

    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. return 0
    • inductive case 1 - the list of items is not empty; ie, there must be at least one item. if the item is a list, return its sum plus the sum of the rest of the items
    • inductive case 2 - there is at least one item that is not an array. return this item plus the sum of the rest of the items

    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.


    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

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

    0 讨论(0)
提交回复
热议问题