3

I would like to remove an element from an array that is inside an object and override that object with the new values. See example below.

var obj = {
  a: [1, 2, 3],
  b: [4, 5, 6],
  c: [7, 8, 9]
}

I would like to remove the number 5 from obj without knowing in which array the element is.

I am trying to update a state in react using the Context API. It should directly return the object itself.

case ACTION: return {
  ...state,
  obj: ?
}

Expected final result :

var obj = {
  a: [1, 2, 3],
  b: [4, 6],
  c: [7, 8, 9]
}
2
  • 1
    You tagged this react, are you using this with state? If so the answer is different as you don't want to mutate the array directly. Commented Dec 24, 2020 at 23:31
  • Yes I am using it with react inside a Context Commented Dec 24, 2020 at 23:32

2 Answers 2

1

To generate a new object with updated values, you can use Object.entries() to convert the object to entries of [key, value]. Map the entries, and filter the values array, and then convert the entries back to an object with Object.fromEntries():

const fn = (obj, item) =>
  Object.fromEntries(
    Object.entries(obj)
      .map(([k, v]) => [k, v.filter(o => o !== item)])
  )

const obj = {
  a: [1, 2, 3],
  b: [4, 6],
  c: [7, 8, 9]
}

const result = fn(obj, 5)

console.log(result)

There is a slight problem here that might cause unnecessary rendering - since we filter all arrays, each array is new, even if the item doesn't exist in that array to start with. We can solve that by check if an array actually contain the item before filtering it. This might be premature optimization, and should be profiled.

const fn = (obj, item) =>
  Object.fromEntries(
    Object.entries(obj)
      .map(e => e[1].includes(item) ? [e[0], e[1].filter(o => o !== item)] : e)
  )

const obj = {
  a: [1, 2, 3],
  b: [4, 6],
  c: [7, 8, 9]
}

const result = fn(obj, 5)

console.log(result.c === obj.c) // c didn't change

console.log(result)

If Object.fromEntries() is not supported by your environment, you can easily replace it with a function based on Array.reduce():

const fromEntries = entries =>
  entries.reduce((obj, [k, v]) => {
    obj[k] = v
  
    return obj
  }, {})

const fn = (obj, item) =>
  fromEntries(
    Object.entries(obj)
      .map(([k, v]) => [k, v.filter(o => o !== item)])
  )

const obj = {
  a: [1, 2, 3],
  b: [4, 6],
  c: [7, 8, 9]
}

const result = fn(obj, 5)

console.log(result)

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

3 Comments

That's exactly what I was looking. I ran this is vanilla js but is it normal that an error occured in reactjs undefined is not a function near Object.fromEntries?
Object.fromEntries() is supported by all new browsers. It's not supported by IE.
It's easy to replace Object.fromEntries() with a function based on reduce. I'll add an example.
1

The easiest approach, IMHO, would be to splice that array:

obj.b.splice(1, 1);

EDIT:
If you don't know where the item would be (as per the comment), you could go over them all, and filter each array:

const toRemove = 5;
Object.keys(obj).forEach(k => {
    obj[k] = obj[k].filter(i => i != toRemove);
});

9 Comments

As I said to @plichard, it is my fault, I misspoke. I rather wanted to delete an element entered by the user without really knowing where this element is
@CustyZ01 so I misunderstood the question them. See my edited answer.
Thank you for your answer but is that returning an object? For example can I do this: obj = Object.keys(obj).forEach(k => { obj[k] = obj[k].filter(i => i != toRemove); }); I am trying to get back the object to update a react state (see EDIT in question)
@CustyZ01 this updates obj in-place. If you want, you can then return it.
You could probably do obj.b.splice(obj.b.indexOf(5), 1)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.