最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript ES6, best way to remove item from array if it exists or add if doesn't exists - Stack Overflow

programmeradmin3浏览0评论

I'm writing some code here to add an element on an array with the following logic

If the element exists on the array, the function should remove the element from the array and return the array without the given element, otherwise it should return the array with the given element appended on it.

Having this in mind, I'm thinking if there's a better way to do this, this is the code I've writed to do this.

function filterArray(arr, obj, key) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i][key] === obj[key]) {
      const newArr = [...arr]
      newArr.splice(i, 1)
      return newArr
    }
  }
  return [...arr, obj]
}

const fruits = [
  { id: 1, fruit: "Apple" },
  { id: 2, fruit: "Banana" },
  { id: 3, fruit: "Pineapple" }
]

const removedBanana = filterArray(fruits, {
  id: 3,
  fruit: "Banana"
}, "fruit")

const addedStrawberry = filterArray(fruits, {
  id: 4,
  fruit: "Strawberry"
}, "fruit")

console.log(removedBanana) // [ { id: 1, fruit: 'Apple' }, { id: 3, fruit: 'Pineapple' } ]
console.log(addedStrawberry)
// [
//   { id: 1, fruit: 'Apple' },
//   { id: 2, fruit: 'Banana' },
//   { id: 3, fruit: 'Pineapple' },
//   { id: 4, fruit: 'Strawberry' }
// ]

I'm writing some code here to add an element on an array with the following logic

If the element exists on the array, the function should remove the element from the array and return the array without the given element, otherwise it should return the array with the given element appended on it.

Having this in mind, I'm thinking if there's a better way to do this, this is the code I've writed to do this.

function filterArray(arr, obj, key) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i][key] === obj[key]) {
      const newArr = [...arr]
      newArr.splice(i, 1)
      return newArr
    }
  }
  return [...arr, obj]
}

const fruits = [
  { id: 1, fruit: "Apple" },
  { id: 2, fruit: "Banana" },
  { id: 3, fruit: "Pineapple" }
]

const removedBanana = filterArray(fruits, {
  id: 3,
  fruit: "Banana"
}, "fruit")

const addedStrawberry = filterArray(fruits, {
  id: 4,
  fruit: "Strawberry"
}, "fruit")

console.log(removedBanana) // [ { id: 1, fruit: 'Apple' }, { id: 3, fruit: 'Pineapple' } ]
console.log(addedStrawberry)
// [
//   { id: 1, fruit: 'Apple' },
//   { id: 2, fruit: 'Banana' },
//   { id: 3, fruit: 'Pineapple' },
//   { id: 4, fruit: 'Strawberry' }
// ]

There's a better way to do this on ES6?

EDIT
If possible, I want to iterate the array only one time, making an O(n) algorithm

Share Improve this question edited Jan 10, 2020 at 13:12 Ricardo Mendes asked Jan 10, 2020 at 13:04 Ricardo MendesRicardo Mendes 3491 gold badge5 silver badges14 bronze badges 4
  • do you want to mutate the array? – Nina Scholz Commented Jan 10, 2020 at 13:05
  • @NinaScholz yes – Ricardo Mendes Commented Jan 10, 2020 at 13:05
  • your code shows a new array ... – Nina Scholz Commented Jan 10, 2020 at 13:08
  • Ops, sorry @NinaScholz, I don't want to mutate, I want to create a new one – Ricardo Mendes Commented Jan 10, 2020 at 13:41
Add a comment  | 

4 Answers 4

Reset to default 8

This approach mutates the array by looking for the index and splice if found or push the object to the array. The result has the same object reference than the handed over array.

function filterArray(array, object, key) {
    var index = array.findIndex(o => o[key] === object[key]);
    if (index === -1) array.push(object);
    else array.splice(index, 1);
    return array;
}

const
    fruits = [{ id: 1, fruit: "Apple" }, { id: 2, fruit: "Banana" }, { id: 3, fruit: "Pineapple" }];

console.log(filterArray(fruits, { id: 3, fruit: "Banana" }, "fruit"));
console.log(filterArray(fruits, { id: 4, fruit: "Strawberry" }, "fruit"));
.as-console-wrapper { max-height: 100% !important; top: 0; }

For a nonmutating approach, you could get a copy in the head of the function and perform the same as above.

function filterArray([...array], object, key) {

function filterArray(array, object, key) {
    var index = array.findIndex(o => o[key] === object[key]);
    if (index === -1) array.push(object);
    else array.splice(index, 1);
    return array;
}

const
    fruits = [{ id: 1, fruit: "Apple" }, { id: 2, fruit: "Banana" }, { id: 3, fruit: "Pineapple" }];

console.log(filterArray(fruits, { id: 3, fruit: "Banana" }, "fruit"));
console.log(filterArray(fruits, { id: 4, fruit: "Strawberry" }, "fruit"));
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can use Array.some() to check if the object exists, and if it does filter it out. If not, add it.

function filterArray(arr, obj, key) {
  return arr.some(o => obj[key] === o[key]) ? // if you can find the object
    arr.filter(o => obj[key] !== o[key]) // remove it
    :  
    [...arr, obj] // or add it if not
}

const fruits = [{"id":1,"fruit":"Apple"},{"id":2,"fruit":"Banana"},{"id":3,"fruit":"Pineapple"}]

const removedBanana = filterArray(fruits, { id: 3, fruit: "Banana" }, "fruit")
const addedStrawberry = filterArray(fruits, { id: 4, fruit: "Strawberry" }, "fruit")

console.log(removedBanana) // [ { id: 1, fruit: 'Apple' }, { id: 3, fruit: 'Pineapple' } ]
console.log(addedStrawberry)
// [
//   { id: 1, fruit: 'Apple' },
//   { id: 2, fruit: 'Banana' },
//   { id: 3, fruit: 'Pineapple' },
//   { id: 4, fruit: 'Strawberry' }
// ]

There is a simple solution for this question:

function addObjToArray (arr, obj, key) {
  const resultArr = arr.filter(arrObj => arrObj[key] !== obj[key])
  if (resultArr.length === arr.length) resultArr.push(obj)
  return resultArr
}

The filter method will return an array with just objects that are different of obj[key]. If filtered array is equal to original array, it push the object to resultArr, else, just will return the initial resultArr.

This is solution from my work colleague (https://stackoverflow.com/users/12691758/guilherme-ca%c3%a7ador-monteiro).

What you think?

By your requirements, and the additional requirement -- in comments -- that the collection should mutate, you would have a better tool by using an ES6 Map:

const fruits = new Map([
  { id: 1, fruit: "Apple" },
  { id: 2, fruit: "Banana" },
  { id: 3, fruit: "Pineapple" }
].map (o => [o.fruit, o]));
fruits.key = "fruit"; // register the key field once
fruits.toggleItem = function (obj) {
    if (!this.delete(obj[this.key])) this.set(obj[this.key], obj);
}

fruits.toggleItem({id: 3, fruit: "Banana"});

console.log([...fruits.values()]);

fruits.toggleItem({id: 4, fruit: "Strawberry"});

console.log([...fruits.values()]);

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论