1

I'm trying to modify the values in depth in array in nested array and objects but it seems it's making clone of array I tried to do it recursively.

I'm trying to edit each Boolean values to false :

 let data = [{ arr: [true, true, false, false], one: { first: [false, true, true, [true, true, false, false, { arr: [true, { tree: { data: { data: { dd: [true, true, false, false, true] } } } }] }]] } }]


  // change all Boolean values to false in example

  actionOnArray(array) {
    array = array.map((ele) => {
      typeof ele === "boolean" && (ele = false)
      return ele
    })
  }


  findArrayInDepth(array, action) {
    if (Array.isArray(array)) {
      actionOnArray(array)
      for (let i = 0; i < array.length; i++) {
        if (Array.isArray(array[i]) || (typeof array === "object" && array !== null)) {
          findArrayInDepth(array[i], action)
        }
      }
    } else if (typeof array === "object" && array !== null) {
      for (let key in array) {
        if (Array.isArray(array) || (typeof array === "object" && array !== null)) {
          findArrayInDepth(array[key], action)
        }
      }
    }
  }


findArrayInDepth(data)

console.log(data) // will output the same original array

Dex
  • 137
  • 2
  • 10
atallah salah
  • 17
  • 1
  • 8

2 Answers2

1

The problem is here:

actionOnArray(array) {
  array = array.map((ele) => {
    typeof ele === "boolean" && (ele = false)
    return ele
  })
}

array.map returns a new array, but when you do array = array.map... you are not changing the initial array, you are only reassigning your array local variable, so it now references the new array. When you call actionOnArray(array) you only pass the reference to your array, so when this reference is reassigned it doesn't affect the array contents.

What you need to do is to iterate over the array using a for loop and reassign each of its items:

function actionOnArray(array) {
  for (let i = 0; i < array.length; i++) { 
    typeof array[i] === "boolean" && (array[i] = false);
  }
}

let data = [{ arr: [true, true, false, false], one: { first: [false, true, true, [true, true, false, false, { arr: [true, { tree: { data: { data: { dd: [true, true, false, false, true] } } } }] }]] } }];


// change all Boolean values to false in example

function actionOnArray(array) {
  for (let i = 0; i < array.length; i++) { 
    typeof array[i] === "boolean" && (array[i] = false);
  }
}


function findArrayInDepth(array, action) {
  if (Array.isArray(array)) {
    actionOnArray(array)
    for (let i = 0; i < array.length; i++) {
      if (Array.isArray(array[i]) || (typeof array === "object" && array !== null)) {
        findArrayInDepth(array[i], action);
      }
    }
  } else if (typeof array === "object" && array !== null) {
    for (let key in array) {
      if (Array.isArray(array) || (typeof array === "object" && array !== null)) {
        findArrayInDepth(array[key], action);
      }
    }
  }
}


findArrayInDepth(data);

console.log(data);

Note: if you use

array.forEach((ele) => {
  typeof ele === "boolean" && (ele = false)
})

it won't change the contents either, because (ele) => {...} is a function and hence ele is a local variable. This means that if ele is a primitive, it will be just a copy of the actual array item.

Take a look at this answer for the detailed explanation: https://stackoverflow.com/a/31298343/8629960

Kirill Simonov
  • 8,257
  • 3
  • 18
  • 42
1

We can write a higher-order mutation function, mut, that takes a user-supplied function, f, for rewriting values on the input, x -

const identity = x =>
  x

const mut = (f = identity, x = {}) =>
  Object(x) === x
    ? Object
        .entries(x)
        .reduce
          ( (r, [ k, v ]) => 
              Object.assign(r, { [k]: mut (f, v) })
          , x
          )
    : f (x)

Now to solve your problem... For any value, v, if it is a Boolean, we will return its inverse, !v. Otherwise if v is not a Boolean, we will return v untouched. We encode that as -

mut (v => typeof v === 'boolean' ? !v : v, data)

Verify it works by running the snippet below -

const mut = (f, x = {}) =>
  Object(x) === x
    ? Object
        .entries(x)
        .reduce
          ( (r, [ k, v ]) => 
              Object.assign(r, { [k]: mut (f, v) })
          , x
          )
    : f (x)


let data =
  [{ arr: [true, true, false, false], one: { first: [false, true, true, [true, true, false, false, { arr: [true, { tree: { data: { data: { dd: [true, true, false, false, true] } } } }] }]] } }]

console.log(JSON.stringify(data))

mut (v => typeof v === 'boolean' ? !v : v, data)

console.log(JSON.stringify(data))
Mulan
  • 129,518
  • 31
  • 228
  • 259