Javascript ES6,如果存在则从数组中删除项目的最佳方法,如果不存在则添加

Posted

技术标签:

【中文标题】Javascript ES6,如果存在则从数组中删除项目的最佳方法,如果不存在则添加【英文标题】:Javascript ES6, best way to remove item from array if it exists or add if doesn't exists 【发布时间】:2020-04-28 03:20:41 【问题描述】:

我在这里写了一些代码,用以下逻辑在数组上添加一个元素

如果该元素存在于数组中,该函数应该从数组中移除该元素并返回没有给定元素的数组,否则它应该返回附加给定元素的数组。

考虑到这一点,我正在考虑是否有更好的方法来做到这一点,这就是我为此编写的代码。

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' 
// ]

在 ES6 上有更好的方法吗?

编辑 如果可能的话,我想只迭代一次数组,做一个 O(n) 算法

【问题讨论】:

你想改变数组吗? @NinaScholz 是的 您的代码显示了一个新数组 ... 操作,对不起@NinaScholz,我不想变异,我想创建一个新的 【参考方案1】:

这个问题有一个简单的解决方案:

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

filter 方法将返回一个数组,其中仅包含与obj[key] 不同的对象。如果过滤后的数组等于原始数组,则将对象推送到resultArr,否则,将返回初始的resultArr

这是我的同事 (https://***.com/users/12691758/guilherme-ca%c3%a7ador-monteiro) 提供的解决方案。

你怎么看?

【讨论】:

来自***.com/users/12691758/…【参考方案2】:

这种方法通过查找索引和拼接(如果找到)或将对象推送到数组来改变数组。结果与移交的数组具有相同的对象引用。

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; 

对于非变异方法,您可以在函数头部获取副本并执行与上述相同的操作。

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; 

【讨论】:

将不得不移动到杜塞尔多夫前 12 小时的某个时区才能有机会获得一些代表。会用三元运算符做到这一点,但 splice()/push() 夫妇似乎在这种特殊情况(尤其是与findIndex() 一起)。赞成。 @YevgenGorbunkov,三元组不起作用,因为参数不同。 三元运算符 works 非常适合“变异”方法 ...以及在函数参数中使用扩展语法进行非变异【参考方案3】:

根据您的要求,以及附加要求(在 cmets 中)集合应该变异,使用 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()]);

【讨论】:

【参考方案4】:

您可以使用Array.some() 来检查对象是否存在,以及是否将其过滤掉。如果没有,请添加它。

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' 
// ]

【讨论】:

filter() 循环遍历整个数组,some() 循环直到匹配在最坏的情况下 2 次通过。仍然是 O(n),但似乎不是性能最好的解决方案。我猜,there's 更短。 注意解决方案之间的区别 - 我的不会改变数组。为了使事物在没有过滤器的情况下保持不变,您仍然需要首先找到项目的索引 - O(n),如果存在,也复制数组 (O(n))。所以不可变需要 O(2n) -> O(n)。

以上是关于Javascript ES6,如果存在则从数组中删除项目的最佳方法,如果不存在则添加的主要内容,如果未能解决你的问题,请参考以下文章

如果数组不存在,则从现有 URL 将数组插入到页面链接 url 中创建数组,将默认值插入到页面上的 href 链接中

比较两个数组的有效方法

如果连接存在,则从连接表返回值

ES6新增方法

JavaScript 之 ES6 中数组做了哪些新扩展?

1144: 零起点学算法51——数组中删数