如果项目具有相同的ID,则将项目添加到数组或替换它

时间:2021-06-13 22:04:42

I have this array of objects

我有这个对象数组

var source = [
  {id: 1, label: "one"},
  {id: 2, label: "two"},
  {id: 3, label: "three"}
];

I need to add an item or substitute it if it has the same id

如果它具有相同的ID,我需要添加一个项目或替换它

var new_sub = {id: 1, label: "new label for one"};
var new_add = {id: 4, label: "four"};

source = myFunc(new_sub);
source = myFunc(new_add);

function myFunc(obj) {
  return (source.findIndex(x => x.id === obj.id) === -1) ? 
  source.concat(obj) : source.map((item) => {
    return (item.id === obj.id) ? obj : item;
  });
}

This code works perfectly, but is there a better way to do this? You can check my code to this snippit:

这段代码完美无缺,但还有更好的方法吗?你可以检查我的代码到这个snippit:

var source = [
      {id: 1, label: "one"},
      {id: 2, label: "two"},
      {id: 3, label: "three"}
    ];
var new_sub = {id: 1, label: "new label for one"};
var new_add = {id: 4, label: "four"};

source = myFunc(new_sub);
source = myFunc(new_add);

function myFunc(obj) {
  return (source.findIndex(x => x.id === obj.id) === -1) ? 
  	source.concat(obj) : source.map((item) => {
    	return (item.id === obj.id) ? obj : item;
    });
}

//PRINT
var html = "";
source.map((item) => {
	html += "<li>" + item.id + " - " + item.label + "</li>";
});
$("#resp").html(html);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="resp">
</ul>

4 个解决方案

#1


1  

You're making multiple passes over the array (one in findIndex, then one in either concat or map), which is unnecessary. Just a single pass will do it:

你正在对数组进行多次传递(一个在findIndex中,然后一个在concat或map中),这是不必要的。只需一次通过即可:

function myFunc(a, obj) {
  let found = false;
  const result = a.map(e => {
    if (!found && e.id === obj.id) {
      found = true;
      return obj;
    } else {
      return e;
    }
  });
  if (!found) {
    result.push(obj);
  }
  return result;
}

Note that I passed the source array into the function as an argument, so it doesn't have side-effects.

请注意,我将源数组作为参数传递给函数,因此它没有副作用。

var source = [
  {id: 1, label: "one"},
  {id: 2, label: "two"},
  {id: 3, label: "three"}
];

var new_sub = {id: 1, label: "new label for one"};
var new_add = {id: 4, label: "four"};

source = myFunc(source, new_sub);
source = myFunc(source, new_add);

console.log(source);

function myFunc(a, obj) {
  let found = false;
  const result = a.map(e => {
    if (!found && e.id === obj.id) {
      found = true;
      return obj;
    } else {
      return e;
    }
  });
  if (!found) {
    result.push(obj);
  }
  return result;
}

Of course, if the array is small and you know that's the standard case, it doesn't really matter.

当然,如果阵列很小并且您知道这是标准情况,那么它并不重要。

If you want to be concise at the expense of (in my view) abusing the , operator:

如果你想简明扼要地(在我看来)滥用运营商:

function myFunc(a, obj) {
  let found = false;
  const result = a.map(e => e.id === obj.id ? (found = true, obj) : e);
  if (!found) {
    result.push(obj);
  }
  return result;
}

#2


1  

function myFunc(obj) {
  let i = source.findIndex(x => x.id === obj.id); // get the index
  if(i === -1) sources.push(obj);                 // if there isn't any object that have the same id, then push this obj into the array
  else sources[i] = obj;                          // if there is then replace it
  return sources;                                 // this won't be necessary the array get mutated so no need to store it back into sources (see note bellow)
}

Note: Your version of myFunc creates a new array each time it is called. My version doesn't. But since you are storing the return value of myFunc back into sources, I guess creating a new array isn't needed (in my version you won't have to do sources = myFunc(...) as the array sources get mutated).

注意:您的myFunc版本每次调用时都会创建一个新数组。我的版本没有。但是因为你将myFunc的返回值存回到源代码中,我想不需要创建一个新数组(在我的版本中,你不必执行sources = myFunc(...),因为数组源会发生变异) 。

Older browsers support: (and actually better)

较旧的浏览器支持:(实际上更好)

function myFunc(obj) {
  for (var i = 0; i < sources.length && sources[i].id !== obj.id; i++) // stop when reaching the end of the array or when we find an object with the same id
    ;                                                                  // empty loop (just using it to find the index)
  sources[i] = obj;                                                    // i will be either the index of the found object (so it will be replaced by obj) or sources.length (so obj will be added to the array)
}

#3


0  

If you do this often (insert a few thousand elements) it may be better (concerning performance) to build up a hash table ( which has a lookup time of O(1) instead of O(n) for searching an array):

如果经常这样做(插入几千个元素),建立一个哈希表(查找时间为O(1)而不是O(n)用于搜索数组)可能更好(关于性能):

var source = [
  {id: 1, label: "one"},
  {id: 2, label: "two"},
  {id: 3, label: "three"}
];
var hash = new Map(source.map((el,i)=>[el.id,i]));

function substitute(elem){
  var i = hash.get(elem.id);
  if(i !== undefined){
    return source[i] = elem;
  }
  hash.set(elem.id,source.push(elem));
}

In action

在行动中

#4


0  

    
    function myFunc( o )
    {
      let i ;
      if ( (i = source[0].indexOf(o.id)) < 0 )
      {
        source[0].push(o.id) ; source.push(o)
      }
      else
      {
        source[1 + i] = o
      }
      // return JSON.parse(JSON.stringify(source)) // new Array with primitives
      return source  // As reference
    }
    
    var source = [
        [4, 1, 3, 2] // the trick here
      , {id: 4, label: "four"}
      , {id: 1, label: "one"}
      , {id: 3, label: "three"}
      , {id: 2, label: "two"}
    ];
    
    var new_sub = {id: 1, label: "new label for one"};
    var new_add = {id: 6, label: "six new label"};
    
    source = myFunc(new_sub);
    
    console.log("// => source after new sub", source);
    
    source = myFunc(new_add);
    
    console.log("// => source after new add", source);

#1


1  

You're making multiple passes over the array (one in findIndex, then one in either concat or map), which is unnecessary. Just a single pass will do it:

你正在对数组进行多次传递(一个在findIndex中,然后一个在concat或map中),这是不必要的。只需一次通过即可:

function myFunc(a, obj) {
  let found = false;
  const result = a.map(e => {
    if (!found && e.id === obj.id) {
      found = true;
      return obj;
    } else {
      return e;
    }
  });
  if (!found) {
    result.push(obj);
  }
  return result;
}

Note that I passed the source array into the function as an argument, so it doesn't have side-effects.

请注意,我将源数组作为参数传递给函数,因此它没有副作用。

var source = [
  {id: 1, label: "one"},
  {id: 2, label: "two"},
  {id: 3, label: "three"}
];

var new_sub = {id: 1, label: "new label for one"};
var new_add = {id: 4, label: "four"};

source = myFunc(source, new_sub);
source = myFunc(source, new_add);

console.log(source);

function myFunc(a, obj) {
  let found = false;
  const result = a.map(e => {
    if (!found && e.id === obj.id) {
      found = true;
      return obj;
    } else {
      return e;
    }
  });
  if (!found) {
    result.push(obj);
  }
  return result;
}

Of course, if the array is small and you know that's the standard case, it doesn't really matter.

当然,如果阵列很小并且您知道这是标准情况,那么它并不重要。

If you want to be concise at the expense of (in my view) abusing the , operator:

如果你想简明扼要地(在我看来)滥用运营商:

function myFunc(a, obj) {
  let found = false;
  const result = a.map(e => e.id === obj.id ? (found = true, obj) : e);
  if (!found) {
    result.push(obj);
  }
  return result;
}

#2


1  

function myFunc(obj) {
  let i = source.findIndex(x => x.id === obj.id); // get the index
  if(i === -1) sources.push(obj);                 // if there isn't any object that have the same id, then push this obj into the array
  else sources[i] = obj;                          // if there is then replace it
  return sources;                                 // this won't be necessary the array get mutated so no need to store it back into sources (see note bellow)
}

Note: Your version of myFunc creates a new array each time it is called. My version doesn't. But since you are storing the return value of myFunc back into sources, I guess creating a new array isn't needed (in my version you won't have to do sources = myFunc(...) as the array sources get mutated).

注意:您的myFunc版本每次调用时都会创建一个新数组。我的版本没有。但是因为你将myFunc的返回值存回到源代码中,我想不需要创建一个新数组(在我的版本中,你不必执行sources = myFunc(...),因为数组源会发生变异) 。

Older browsers support: (and actually better)

较旧的浏览器支持:(实际上更好)

function myFunc(obj) {
  for (var i = 0; i < sources.length && sources[i].id !== obj.id; i++) // stop when reaching the end of the array or when we find an object with the same id
    ;                                                                  // empty loop (just using it to find the index)
  sources[i] = obj;                                                    // i will be either the index of the found object (so it will be replaced by obj) or sources.length (so obj will be added to the array)
}

#3


0  

If you do this often (insert a few thousand elements) it may be better (concerning performance) to build up a hash table ( which has a lookup time of O(1) instead of O(n) for searching an array):

如果经常这样做(插入几千个元素),建立一个哈希表(查找时间为O(1)而不是O(n)用于搜索数组)可能更好(关于性能):

var source = [
  {id: 1, label: "one"},
  {id: 2, label: "two"},
  {id: 3, label: "three"}
];
var hash = new Map(source.map((el,i)=>[el.id,i]));

function substitute(elem){
  var i = hash.get(elem.id);
  if(i !== undefined){
    return source[i] = elem;
  }
  hash.set(elem.id,source.push(elem));
}

In action

在行动中

#4


0  

    
    function myFunc( o )
    {
      let i ;
      if ( (i = source[0].indexOf(o.id)) < 0 )
      {
        source[0].push(o.id) ; source.push(o)
      }
      else
      {
        source[1 + i] = o
      }
      // return JSON.parse(JSON.stringify(source)) // new Array with primitives
      return source  // As reference
    }
    
    var source = [
        [4, 1, 3, 2] // the trick here
      , {id: 4, label: "four"}
      , {id: 1, label: "one"}
      , {id: 3, label: "three"}
      , {id: 2, label: "two"}
    ];
    
    var new_sub = {id: 1, label: "new label for one"};
    var new_add = {id: 6, label: "six new label"};
    
    source = myFunc(new_sub);
    
    console.log("// => source after new sub", source);
    
    source = myFunc(new_add);
    
    console.log("// => source after new add", source);