0

I can't understant result of use array reduce to find max property

I'm trying to add node to array, while adding I'd like to add id to node. Here is example to test

localNodes: [
    {id:0, x:20, y:20},
    {id:1, x:50, y:50}
]

addNode(node){
  let maxId = localNodes.reduce( (a, b) => Math.max(a.id, b.id) ); 
  maxId++
  //localNodes.push({id:maxId, ...node})
  localNodes.push({id:maxId, x:node.x, y:node.y})
}

addNode({x:20, y:20})
addNode({x:20, y:20})
addNode({x:20, y:20})

Here is strange results:

  • Added nodes in array looks like 'Observer'
  • first added node have correctly calculated id = 2
  • all following nodes have id set to NaN

Output:

localNodes: Array(5)
0: {…}
1: {…}
2: {__ob__: Observer}    -> id = 2
3: {__ob__: Observer}    -> id = NaN
4: {__ob__: Observer}    -> id = NaN

Could you please explain what I did wrong and may be point how to fix it.

1
  • 1
    You are not returning an object.... Reduce code is wrong Commented Apr 24, 2019 at 20:18

1 Answer 1

1

First of all let's look at the definition of the reduce function

it takes a function with four arguments

Array​.prototype​.reduce((accumulator, currentValue, currentIndex, array) => {
    // the function must return a value.
    // accumulator: the accumulator accumulates the return value. 
    // currentValue: The current element being processed in the array.
    // currentIndex: The index of the current element being processed in the array. Starts at index 0 if an initialValue is provided and at index 1 otherwise.
    // array: The array reduce() was called upon.  
}, initialValue);

if you don't provide an initial value, the accumulator will be the first element and the currentValue will be the second element in the array


Now the first time you run your function it returns 1 because there's only two values to check

translates to this

// a = accumulator = {id:0, x:20, y:20}
// b = currentValue= {id:1, x:50, y:50}
Math.max(a.id, b.id) 

which is fine, however when there's more this happens

First cycle

// a = accumulator = {id:0, x:20, y:20}
// b = currentValue= {id:1, x:50, y:50}
Math.max(a.id, b.id)  // return 1

Second cycle

// a = accumulator = 1 returned from the first cycle
// b = currentValue= {id:2, x:20, y:20}
Math.max(a.id, b.id) // returns NaN because 1.id doesn't makes sense

Solution

let localNodes = [
    {id:0, x:20, y:20},
    {id:1, x:50, y:50}
]

function addNode(node){
  let maxId = localNodes.reduce( (accumulator, currentValue) => {
    /*
      here we gonna start with 0 which means the accumulator
      will equal 0 at the first cycle and the currentValue
      will be the first element in the array
    */
    Math.max(accumulator,currentValue.id)
  },0); 
  
  maxId++
  localNodes.push({id:maxId, x:node.x, y:node.y})
}

addNode({x:20, y:20})
addNode({x:20, y:20})
addNode({x:20, y:20})

console.log(localNodes)
.as-console-wrapper {
  max-height: 100% !important;
}

Sign up to request clarification or add additional context in comments.

4 Comments

Your solution in the reduce function is missing "id" for a.id Math.max(a,b.id). Also worth mentioning that OP's original code had a syntax error with initializing the localNodes array. It should be let localNodes = []; not let localNodes : [];
i don't think that a typo, it's probably a class definition or the OP could be coming from a different environment and forgot to correct the syntax also Math.max(a,b.id) is fine i edited the answer with better names so you can understand.
Ah, gotcha. Thanks for the clarification!
@Zohir Salak Thank you a lot!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.