Есть ли indexOf в javascript для поиска массива с пользовательской функцией сравнения

Мне нужен индекс первого значения в массиве, который соответствует пользовательской функции сравнения.

Очень приятный underscorej имеет функцию "найти", которая возвращает первое значение, когда функция возвращает true, но мне понадобится это возвращает индекс. Есть ли версия indexOf, доступная где-нибудь, где я могу передать функцию, используемую для сравнения?

Спасибо за любые предложения!

Ответ 1

Здесь используется способ Underscore - это увеличивает основную функцию Underscore с той, которая принимает функцию итератора:

// 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

Ответ 2

Вы можете сделать что-то вроде этого:

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

Относительно христианского комментария: если вы переопределите стандартный метод JavaScript с помощью настраиваемого с другого той же самой сигнатуры и разных функций, то, вероятно, произойдет что-то плохое. Это особенно верно, если вы занимаетесь сторонними библиотеками, которые могут зависеть от оригинала, скажем, Array.proto.indexOf. Так что да, вы, вероятно, захотите назвать это чем-то другим.

Ответ 3

Там предложение для Array.prototype.findIndex() в Harmony (ECMAScript 6). В настоящее время он реализован в Firefox и Safari. Здесь polyfill, любезно предоставлено Mozilla Developer Network:

if (!Array.prototype.findIndex) {
  Array.prototype.findIndex = function(predicate) {
    if (this == null) {
      throw new TypeError('Array.prototype.find called on null or undefined');
    }
    if (typeof predicate !== 'function') {
      throw new TypeError('predicate must be a function');
    }
    var list = Object(this);
    var length = list.length >>> 0;
    var thisArg = arguments[1];
    var value;

    for (var i = 0; i < length; i++) {
      value = list[i];
      if (predicate.call(thisArg, value, i, list)) {
        return i;
      }
    }
    return -1;
  };
}

Ответ 4

Как отмечали другие, достаточно легко сворачивать свои собственные, которые вы можете сохранить в своем конкретном варианте использования:

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

Или, если вы CoffeeScripter:

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

Ответ 5

Метод массива javascript фильтр возвращает подмножество массива, возвращающего значение true из переданной функции.

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

Ответ 6

Как насчет такой функции поиска?

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

Ответ 7

Здесь идет кофейная версия 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
})

Ответ 8

с использованием подчеркивания. Я придумал что-то, скопированное из их реализации, используя _.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;
};

Как вы думаете, есть ли у вас лучшие решения?