web-dev-qa-db-fra.com

Existe-t-il un indexOf en javascript pour rechercher un tableau avec une fonction de comparaison personnalisée

J'ai besoin de l'index de la première valeur du tableau, qui correspond à une fonction de comparaison personnalisée.

Le très Nice nderscorej a une fonction "find" qui retourne la première valeur où une fonction retourne true, mais j'aurais besoin de cela qui retourne l'index à la place. Y a-t-il une version d'indexOf disponible quelque part, où je peux passer une fonction utilisée pour comparer?

Merci pour toutes suggestions!

27
Pedi T.

Voici la méthode Underscore pour le faire - cela augmente la fonction Underscore de base avec une qui accepte une fonction itérateur:

// save a reference to the core implementation
var indexOfValue = _.indexOf;

// using .mixin allows both wrapped and unwrapped calls:
// _(array).indexOf(...) and _.indexOf(array, ...)
_.mixin({

    // return the index of the first array element passing a test
    indexOf: function(array, test) {
        // delegate to standard indexOf if the test isn't a function
        if (!_.isFunction(test)) return indexOfValue(array, test);
        // otherwise, look for the index
        for (var x = 0; x < array.length; x++) {
            if (test(array[x])) return x;
        }
        // not found, return fail value
        return -1;
    }

});

_.indexOf([1,2,3], 3); // 2
_.indexOf([1,2,3], function(el) { return el > 2; } ); // 2
26
nrabinowitz

Il y a ne fonction standard dans ECMAScript 2015 pour Array.prototype.findIndex(). Actuellement, il est implémenté dans tous les principaux navigateurs, à l'exception d'Internet Explorer.

Voici un polyfill, gracieuseté de Mozilla Developer Network :

// https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
if (!Array.prototype.findIndex) {
  Object.defineProperty(Array.prototype, 'findIndex', {
    value: function(predicate) {
     // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      var thisArg = arguments[1];

      // 5. Let k be 0.
      var k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return k.
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return k;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return -1.
      return -1;
    },
    configurable: true,
    writable: true
  });
}
10
Husky

Vous pouvez faire quelque chose comme ça:

Array.prototype.myIndexOf = function(f)
{
    for(var i=0; i<this.length; ++i)
    {
        if( f(this[i]) )
            return i;
    }
    return -1;
};

Concernant le commentaire de Christian: si vous remplacez une méthode JavaScript standard par une méthode personnalisée avec un autre la même signature et des fonctionnalités différentes, une mauvaise chose se produira probablement. Cela est particulièrement vrai si vous utilisez des bibliothèques tierces qui peuvent dépendre de l'original, par exemple, Array.proto.indexOf. Alors oui, vous voudrez probablement l'appeler autrement.

7

Comme d'autres l'ont noté, il est assez facile de rouler le vôtre, que vous pouvez garder court et simple pour votre cas d'utilisation particulier:

// Find the index of the first element in array
// meeting specified condition.
//
var findIndex = function(arr, cond) {
  var i, x;
  for (i in arr) {
    x = arr[i];
    if (cond(x)) return parseInt(i);
  }
};

var moreThanTwo = function(x) { return x > 2 }
var i = findIndex([1, 2, 3, 4], moreThanTwo)

Ou si vous êtes un CoffeeScripter:

findIndex = (arr, cond) ->
  for i, x of arr
    return parseInt(i) if cond(x)
3
joyrexus

Voici la version coffeescript de nrabinowitz code .

# save a reference to the core implementation
indexOfValue = _.indexOf

# using .mixin allows both wrapped and unwrapped calls:
# _(array).indexOf(...) and _.indexOf(array, ...)
_.mixin ({
    # return the index of the first array element passing a test
    indexOf: (array, test) ->
        # delegate to standard indexOf if the test isn't a function
        if (!_.isFunction(test))
            return indexOfValue(array, test)
        # otherwise, look for the index
        for item, i in array
            return i if (test(item))
        # not found, return fail value
        return -1
})
1
Shiva Huang

Que diriez-vous d'une telle fonction de recherche?

(function () {
  if (!Array.prototype._find) {
    Array.prototype._find = function (value) {
      var i = -1, j = this.length;
      if (typeof(value)=="function") 
         for(; (++i < j) && !value(this[i]););
      else
         for(; (++i < j) && !(this[i] === value););

      return i!=j ? i : -1;
    }
  }
}());
1
23W

La méthode du tableau javascript filter renvoie un sous-ensemble du tableau qui renvoie vrai à partir de la fonction passée.

var arr= [1, 2, 3, 4, 5, 6],
first= arr.filter(function(itm){
    return itm>3;
})[0];
alert(first);

if you must support IE before #9 you can 'shim' Array.prototype.filter-

Array.prototype.filter= Array.prototype.filter || function(fun, scope){
    var T= this, A= [], i= 0, itm, L= T.length;
    if(typeof fun== 'function'){
        while(i<L){
            if(i in T){
                itm= T[i];
                if(fun.call(scope, itm, i, T)) A[A.length]= itm;
            }
            ++i;
        }
    }
    return A;
}
1
kennebec

en utilisant le soulignement, j'ai trouvé quelque chose copié à partir de leur implémentation find en utilisant _.any:

findIndex = function (obj, iterator, context) {
    var idx;
    _.any(obj, function (value, index, list) {
        if (iterator.call(context, value, index, list)) {
            idx = index;
            return true;
        }
    });
    return idx;
};

Que pensez-vous - avez-vous de meilleures solutions?

0
Pedi T.