RoundRobin functional approach - why does my function have side effects?

后端 未结 3 1550
一整个雨季
一整个雨季 2021-02-14 09:31

Objective

I am trying to create a Round Robin algorithm ( https://en.wikipedia.org/wiki/Round-robin_scheduling ) in a pure functional way.

This function, is

相关标签:
3条回答
  • 2021-02-14 10:00
    1. If I am using reduce, which is pure, how am I mutating my parameters?

    Function parameters can't really be mutated; a strange thought – but I'm sure you meant the arguments supplied to your function are being mutated. And yeah, that's with .shift as others pointed out

    And for what it's worth, .reduce isn't pure unless the user-supplied lambda is pure

    1. Is there another pure/functional way of implementing roundRobin?

    Yep

    const isEmpty = xs =>
      xs.length === 0
      
    const head = ( [ x , ...xs ] ) =>
      x
      
    const tail = ( [ x , ...xs ] ) =>
      xs
    
    const append = ( xs , x ) =>
      xs.concat ( [ x ] )
      
    const roundRobin = ( [ x , ...xs ] , acc = [] ) =>
      x === undefined
        ? acc
        : isEmpty ( x )
          ? roundRobin ( xs , acc )
          : roundRobin ( append ( xs , tail ( x ) )
                       , append ( acc , head ( x ) )
                       )
    
    const data =
      [ [ 1 , 4 , 7 , 9 ]
      , [ 2 , 5 ]
      , [ 3 , 6 , 8 , 10 , 11 , 12 ]
      ]
                       
    console.log ( roundRobin ( data ) )
    // => [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ]
    
    console.log ( roundRobin ( [ [ 1 , 2 , 3 ] ] ) )
    // => [ 1 , 2 , 3 ]
    
    console.log ( roundRobin ( [] ) )
    // => []

    0 讨论(0)
  • 2021-02-14 10:09

    Array#shift is doing the mutating.

    var array = [0, 1, 2, 3, 4];
    array.shift(); // -> 0
    array; // -> [1, 2, 3, 4];
    

    The easiest way around that is to clone the array. Usually that can be done with Array#concat but since your arrays are nested (though simple) you can do this:

    const roundRobin = (arr, results) => {
        arr = JSON.parse(JSON.stringify(arr));
        if (arr.length === 0) return results;
        // ...
    

    If you're concerned that the global JSON makes the function impure, you can abstract that out.

    const deepClone = (obj) => JSON.parse(JSON.stringify(obj));
    roundRobin(deepClone(array), []);
    
    0 讨论(0)
  • 2021-02-14 10:09

    Easy way to make immutable object in JS is to use Object.freeze.

    I created your input array as:

    const array1 = Object.freeze([
        Object.freeze([ 1, 2 ]),
        Object.freeze([ 3, 4 ])
    ])
    

    Then, when I tried to call your function I got:

    Uncaught TypeError: Cannot add/remove sealed array elements
    at Array.shift (<anonymous>)
    at arr.reduce (<anonymous>:7:38)
    at Array.reduce (<anonymous>)
    at roundRobin (<anonymous>:4:28)
    at <anonymous>:6:17
    

    You're using shift, which is mutating orignal array.

    Replace it with Array.slice(0,1)[0] and it will start working.

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