11

Following an old question, I still have a problem:

a = ["apple", "banana", "orange", "apple"];

a.indexOf("apple") = 0

What is the easiest way to find BOTH indexes of "apple" element in array? I want to delete them both at once - is it possible?

2
  • 2
    Great question which, while simple at the onset, has produced a variety of answers and all different approaches. I learned something from these answers, and thank you for asking the question. Commented Feb 9, 2014 at 18:11
  • Question title is misleading. Unfortunately, it comes up in Google search. Commented Oct 22, 2018 at 13:03

10 Answers 10

15

That's the task for filter method:

var noApples = a.filter(function(el) { return el != "apple"; })
Sign up to request clarification or add additional context in comments.

2 Comments

+1 This is a great answer, and should be preferred where possible. However, it's worth noting that it will not modify the original Array instance, and instead produces a new array instance containing the filtered results. In cases where the original array reference must be modified (these cases are rare), splice may be used instead.
+1 It's also worth noting that the filter method is sadly not supported in IE8 and below.
9

What is the easiest way to find BOTH indexes of "apple" element in array?

You asked that, but also asked about deleting. I'll tackle indexes first, then deletion.

Indexes:

There's no shortcut, you have to loop through it. You can use a simple for loop:

var indexes = [];
var index;

for (index = 0; index < a.length; ++index) {
    if (a[n] === "apple") {
        indexes.push(index);
    }
});

Or two ES5 options: forEach:

var indexes = [];
a.forEach(function(entry, index) {
    if (entry === "apple") {
        indexes.push(index);
    }
});

Or reduce:

var indexes = a.reduce(function(acc, entry, index) {
    if (entry === "apple") {
        acc.push(index);
    }
    return acc;
}, []);

...although frankly that does't really buy you anything over forEach.

Deletion:

From the end of your question:

I want to delete them both at once - is it possible?

Sort of. In ES5, there's a filter function you can use, but it creates a new array.

var newa = a.filter(function(entry) {
    return entry !== "apple";
});

That basically does this (in general terms):

var newa = [];
var index;

for (index = 0; index < a.length; ++index) {
    if (a[n] !== "apple") {
        newa.push(index);
    }
});

8 Comments

forEach is not an option if you need to support IE8. BTW, i'm not the downvoter.
@gearsdigital: 1. Sure it is, it's easily shimmable. 2. I did point out it's ES5-only. 3. I decided to give an example of for as well.
Using Array.reduce() for that purpose is wrong. Why do you need it there?
@c-smile: It's not wrong, in that it does the job. (jsbin.com/purex/1/edit) One of the things about reduce is that it can be used for all sorts of things.
@gearsdigital: Not always, only when I think of something to add. I try to make sure the very first answer is useful and sufficiently-complete (in case I get called away). (I failed at that this time, though; I missed the last sentence of the question until I went back to do a live example!) :-)
|
3

Array.indexOf takes a second, optional argument: the index to start from. You can use this inside a loop to specify to start from the last one.

var indices = [],
    index = 0;

while (true) {
    index = a.indexOf("apple", index);
    if (index < 0) {
        break;
    }
    indices.push(index);
}

Once indexOf returns -1, which signals "no element found", the loop will break. The indices array will then hold the correct indices.

There is an example on the Mozilla page on indexOf which has some equivalent code. I'm not so much of a fan because of the increased duplication, but it is shorter, which is nice.

Comments

2

A for loop will do the trick. Or use forEach as T.J. Crowder suggests in his elegant answer.

I combined both an example of how to get appleIndexes and also how to "delete" them from the original array by virtue of creating a new array with all but apples in it. This is using oldSchool JavaScript :)

a = ["apple", "banana", "orange", "apple"];

appleIndexes = [];
arrayOfNotApples = [];

for (var i = 0; i < a.length; i++)
{
    if (a[i] == "apple")
    {
        appleIndexes.push(i);
    } else {
        arrayOfNotApples.push(a[i]);
    }
}

Comments

2

If you need to remove elements from an array instance without generating a new array, Array.prototype.splice is a good choice:

var a,
    i;
a = ["apple", "banana", "orange", "apple"];
for (i = a.indexOf('apple'); i > -1; i = a.indexOf('apple')) {
    a.splice(i, 1);
}

If you can use a new array instance, then Array.prototype.filter is a better choice:

var a,
    b;
a = ["apple", "banana", "orange", "apple"];
b = a.filter(function (item, index, array) {
    return item !== 'apple';
});

Comments

1

Use the start parameter in array.indexOf(element, start), as described in http://www.w3schools.com/jsref/jsref_indexof_array.asp.

Example:

var a = [1, 3, 4, 1];
var searchElement = 1;
var foundIndices = [];
var startIndex = 0;

while ((index = a.indexOf(searchElement, startIndex)) != -1) {
       foundIndices.push(index);
       startIndex = index + 1;
}
console.log(foundIndices); // Outputs [0, 3];

Comments

1

A good old while loop :

var i = a.length;
while (i--) {
    if (a[i] === 'apple') {
        a.splice(i, 1); 
    }
}

Inside a function :

function removeAll(value, array) {
    var i = array.length;
    while (i--) {
        if (array[i] === value) {
            array.splice(i, 1); 
        }
    }
    return array;
}

Usage :

removeAll('apple', a);

Comments

1

A couple of recursive solutions.

Javascript

function indexesOf(array, searchElement, fromIndex) {
    var result = [],
        index = array.indexOf(searchElement, fromIndex >>> 0);

    if (index === -1) {
        return result;
    }

    return result.concat(index, indexesOf(array, searchElement, index + 1));
}

function removeFrom(array, searchElement, fromIndex) {
    var index = array.indexOf(searchElement, fromIndex >>> 0);

    if (index !== -1) {
        array.splice(index, 1);
        removeFrom(array, searchElement, index);
    }

    return array;
}

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

console.log(indexesOf(a, 0));
console.log(removeFrom(a, 0));

Output

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

On jsFiddle

Comments

1

The fastest, most compatible, route would be to walk the array backwards in a for loop.

for (var a = array.length;a--;)
     if (array[a] == 'apple') array.splice(a,1);

Comments

0

if you want to remove all occurrences, you could also use Array.splice recursively

function remove(list, item) {
    if(list.indexOf(item)<0)
        return list;

    list.splice(list.indexOf(item),1);
    return list;
}

1 Comment

There is no recursion in this code. It will remove 1 occurrence max.

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.