71

Here is my code for javascript for this simple task:

  1. Remove the element if it exists in an array.
  2. Add the element if it is not in an array.

    if(_.contains(this.types,type_id)){
        var index = this.types.indexOf(type_id);
        this.types.splice(index,1);
    }
    else{
        this.types.push(type_id);
    }
    

Is there a more efficient way to do this?

2
  • can you be sure the element is there only once at most ? Commented Jun 17, 2013 at 17:40
  • Yes, one element should be only once in array Commented Jun 17, 2013 at 17:58

8 Answers 8

71

You could do it without a 3rd party library, this would be more efficient, like this. (this only removes the first instance of a value if found, not multiple)

Javascript

var a = [0, 1, 2, 3, 4, 6, 7, 8, 9],
    b = 5,
    c = 6;

function addOrRemove(array, value) {
    var index = array.indexOf(value);

    if (index === -1) {
        array.push(value);
    } else {
        array.splice(index, 1);
    }
}

console.log(a);

addOrRemove(a, b);
console.log(a);

addOrRemove(a, c);
console.log(a);

Output

[0, 1, 2, 3, 4, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 6, 7, 8, 9, 5]
[0, 1, 2, 3, 4, 7, 8, 9, 5] 

On jsfiddle

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

1 Comment

This answer is ill-advised. A third-party library is not inherently less efficient than your own code. In fact, it is generally more efficient with developer resources since you don't need to reinvent the wheel. On top of that, the code shown here has the same suboptimal asymptotic complexity. The accepted answer by 6502, which actually achieves optimal complexity, is much better.
54

For immutable state ( clone array ):

const addOrRemove = (arr, item) => arr.includes(item) ? arr.filter(i => i !== item) : [ ...arr, item ];

see also: Remove properties from objects (JavaScript)

2 Comments

Dont you mean Array.includes?
@SKuijers .includes is a a prototype array method so it's used directly on the array
46

Using lodash "xor" function

_.xor([2, 1], [2, 3]);
// => [1, 3]

If you don't have an array as 2nd parameter you can simpy wrap the variable into an array

var variableToInsertOrRemove = 2;
_.xor([2, 1], [variableToInsertOrRemove]);
// => [1]
_.xor([1, 3], [variableToInsertOrRemove]);
// => [1, 2, 3]

Here's the doc: https://lodash.com/docs/4.16.4#xor

1 Comment

Do note that this returns a new array instead of modifying the original array.
23

If you care about efficiency then may be using an array to implement a set is a bad idea. For example using an object you could do:

function toggle(S, x) {
    S[x] = 1 - (S[x]|0);
}

then after many add/remove operations you can keep only keys where the value is 1

This way every addition/removal is O(1) and you need only one O(n) operation to get the final result.

If keys are all "small" numbers may be a bitmask is even worth the effort (not tested)

function toggle(S, x) {
    var i = x >> 4;
    S[i] = (S[i]|0) ^ (1<<(x&15));
}

1 Comment

+1 for 0(1) possibility, if only we knew what the OP is trying to achieve.
5

Look at this answer of similar question.

Lodash issue

Lodash gist

Code:

function toggle(collection, item) {
  var idx = collection.indexOf(item);
  if (idx !== -1) {
    collection.splice(idx, 1);
  } else {
    collection.push(item);
  }
}

2 Comments

This is just a copy of Xotic750's answer with renamed variables.
This is not a Xotic750 answer! Please read my answer more attentively! The idea was taken from @nnnnnn answer but not Xotic750! And I mentioned it in my answer in the 1st link (stackoverflow.com/a/18765477/2179748) !
2

If "types" can be a Set then

let toggle = type_id => this.types.delete(type_id) || this.types.add(type_id);

Comments

1

Using underscorejs

function toggle(a,b)
{
return _.indexOf(a,b)==-1?_.union(a,[b]):_.without(a,b);
}

Usage:

var a = [1,2,3];
var b = [4];
a = toggle(a,b); // [1,2,3,4]
a = toggle(a,b); // [1,2,3]

Comments

1

Extending Xotic750's answer this will always ensure that toggled elements occur only once in array. You this if your arrays are bit random like user inputs.

function toggleValueInArray(array, value) {
  var index = array.indexOf(value);

  if (index == -1) {
    array.push(value);
  } else {
    do {
      array.splice(index, 1);
      index = array.indexOf(value);
    } while (index != -1);
  }
}


var a = [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9],
  b = 5,
  c = 10;

// toString just for good output
console.log(a.toString());

toggleValueInArray(a, b);
console.log(a.toString());

toggleValueInArray(a, c);
console.log(a.toString());

Comments

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.