Mauro Sala
Mauro Sala

Reputation: 1186

Add item to array or substitute it if it has the same id

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

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:

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>

Upvotes: 4

Views: 114

Answers (4)

user3114072
user3114072

Reputation:

    
    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);

Upvotes: 0

ibrahim mahrir
ibrahim mahrir

Reputation: 31712

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).

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)
}

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138567

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):

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

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1075925

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:

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;
}

Upvotes: 1

Related Questions