简体   繁体   中英

indexOf similar function to return multiple appearance in javascript

When using indexOf, I can just locate the position of the first appearance:

for example:

a=[1,2,4,2];
b=a.indexOf(2);
alert(b) //returns 1

Is there any alternative function to indexOf to find the both position or am I missing something? I am looking for the shortcut. Of course, I can always go for writing a simple look to find it.

indexOf takes a second argument (the starting index)

So a.indexOf(2,2) would give you 3

To generalize, if x = a.indexOf(2) , then the next instance is a.indexOf(2, x+1)

With one loop :

function indexesOf(arr, target) {
    let index = [];
    // For each element, index pushed in index[]
    arr.forEach((el, i) => {
        if (el === target) index.push(i)
    });
    return index;
}
alert(indexesOf([1, 2, 4, 2], 2));  // -> 1, 3

With two loops :

function indexesOf(arr, target) {
  // Map matching elements to their index, and others to null.
  return arr.map(function (el, i) { return (el === target) ? i : null; })
            // Throw out the nulls.
            .filter(function (x) { return x !== null; });
}

alert(indexesOf([1, 2, 4, 2], 2));  // -> 1, 3

As you are using a recent ECMAScript 5 method then you may want to consider using Array.map and Array.filter along with a new Harmony proposed method Object.is

Javascript

var func = {}.is,
    is;

if (typeof func === "function") {
    is = func;
} else {
    is = function is(x, y) {
        if (x === y) {
            if (x === 0) {
                return 1 / x === 1 / y;
            }

            return true;
        }

        var x1 = x,
            y1 = y;

        return x !== x1 && y !== y1;
    };
}

function indexesOf(array, value) {
    if (!Array.isArray(array)) {
        throw new TypeError("First attribute must be an array.");
    }

    return array.map(function (element, index) {
        if (is(value, element)) {
            return index;
        }
    }).filter(function (element) {
        return typeof element === "number";
    });
}

var test = [1, 2, 4, 2];

console.log(indexesOf(test, 2));

Output

[1, 3] 

On jsfiddle

Update: I have been castigated in the past for using loops when people have the strong belief "but this is exactly what these new methods are designed for". So, I am going to present alternative single loop solutions too.

ECMAScript 5 Array.reduce

Javascript

function indexesOf(array, value) {
    if (!Array.isArray(array)) {
        throw new TypeError("First attribute must be an array.");
    }

    return array.reduce(function (previous, current, index) {
        if (is(value, current)) {
            previous.push(index);
        }

        return previous;
    }, []);
}

On jsfiddle

ECMAScript 5 Array.forEach

Javascript

function indexesOf(array, value) {
    if (!Array.isArray(array)) {
        throw new TypeError("First attribute must be an array.");
    }

    var indexes = [];

    array.forEach(function (element, index) {
        if (is(value, element)) {
            indexes.push(index);
        }
    });

    return indexes.
}

On jsfiddle

ECMAScript 5 Array.indexOf

Note: this method is unable to find the indexes of NaN

Could also use Array.lastIndexOf and work in reverse

Javascript

function indexesOf(array, value) {
    if (!Array.isArray(array)) {
        throw new TypeError("First attribute must be an array.");
    }

    var index = array.indexOf(value),
        indexes = [];

    while (index !== -1) {
        indexes.push(index);
        index = array.indexOf(value, index + 1);
    }

    return indexes;
}

On jsfiddle

standard for

Javascript

function indexesOf(array, value) {
    if ({}.toString.call(array) !== "[object Array]") {
        throw new TypeError("First attribute must be an array.");
    }

    var indexes = [],
        length,
        index;

    for (index = 0, length = array.length; index < length; index += 1) {
        if (array.hasOwnProperty(index) && is(value, array[index])) {
            indexes.push(index);
        }
    }

    return indexes;
}

On jsfiddle

Standard while

Javascript

function indexesOf(array, value) {
    if ({}.toString.call(array) !== "[object Array]") {
        throw new TypeError("First attribute must be an array.");
    }

    var length = array.length,
        indexes = []
        index = 0;

    while (index < length) {
        if (array.hasOwnProperty(index) && is(value, array[index])) {
            indexes.push(index);
        }

        index += 1;
    }

    return indexes;
}

On jsfiddle

Standard for...in

Note: This is NOT recommended, but should be fine.

Why is using “for…in” with array iteration such a bad idea?

Javascript

function indexesOf(array, value) {
    if ({}.toString.call(array) !== "[object Array]") {
        throw new TypeError("First attribute must be an array.");
    }

    var indexes = [],
        prop;

    for (prop in array) {
        if (array.hasOwnProperty(prop) && is(+prop, prop >>> 0) && is(value, array[prop])) {
            indexes.push(+prop);
        }
    }

    return indexes;
}

On jsfiddle

Note: All of the solutions here handle both dense and sparse arrays.

And finally a jsperf comparing all of these solutions.

lastIndexOf() gives the index of last occurence.

But if want an array of indices containing all the occurences of a particular element(2 in your case), you have to write a loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM