From d2d6cfe6675d18b058e52785c438a3c1a7502208 Mon Sep 17 00:00:00 2001
From: Jeremy Ashkenas Table of Contents
invoke, pluck,
max, min,
sortBy, sortedIndex,
- sortedIndexOf,
toArray, size
_.sortedIndex([10, 20, 30, 40, 50], 35); => 3 -- -
- sortedIndexOf_.sortedIndexOf(list, value)
-
- Not to be confused with _.sortedIndex, this method works like
- the native indexOf, but uses binary search to efficiently
- find the value in large, already-sorted arrays. Returns -1
- if the value is not present.
-
-_.sortedIndex([10, 20, 30, 40, 50], 30); -=> 2
@@ -599,11 +585,13 @@
- indexOf_.indexOf(array, value)
+ indexOf_.indexOf(array, value, [isSorted])
Returns the index at which value can be found in the array,
or -1 if value is not present in the array. Uses the native
- indexOf function unless it's missing.
+ indexOf function unless it's missing. If you're working with a
+ large array, and you know that the array is already sorted, pass true
+ for isSorted to use a faster binary search.
_.indexOf([1, 2, 3], 2); diff --git a/test/arrays.js b/test/arrays.js index c7553fc57..7219c038e 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -84,6 +84,18 @@ $(document).ready(function() { var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3); equals(result, 1, 'works on an arguments object'); equals(_.indexOf(null, 2), -1, 'handles nulls properly'); + + var numbers = [10, 20, 30, 40, 50], num = 35; + var index = _.indexOf(numbers, num, true); + equals(index, -1, '35 is not in the list'); + + numbers = [10, 20, 30, 40, 50]; num = 40; + index = _.indexOf(numbers, num, true); + equals(index, 3, '40 is in the list'); + + numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40; + index = _.indexOf(numbers, num, true); + equals(index, 1, '40 is in the list'); }); test("arrays: lastIndexOf", function() { diff --git a/test/collections.js b/test/collections.js index 6c0e8830c..442b205f1 100644 --- a/test/collections.js +++ b/test/collections.js @@ -185,20 +185,6 @@ $(document).ready(function() { equals(index, 3, '35 should be inserted at index 3'); }); - test('collections: sortedIndexOf', function() { - var numbers = [10, 20, 30, 40, 50], num = 35; - var index = _.sortedIndexOf(numbers, num); - equals(index, -1, '35 is not in the list'); - - numbers = [10, 20, 30, 40, 50]; num = 40; - index = _.sortedIndexOf(numbers, num); - equals(index, 3, '40 is in the list'); - - numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40; - index = _.sortedIndexOf(numbers, num); - equals(index, 1, '40 is in the list'); - }); - test('collections: toArray', function() { ok(!_.isArray(arguments), 'arguments object is not an array'); ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array'); diff --git a/underscore.js b/underscore.js index 4d0851935..cf11afb5f 100644 --- a/underscore.js +++ b/underscore.js @@ -254,8 +254,6 @@ // Use a comparator function to figure out at what index an object should // be inserted so as to maintain order. Uses binary search. - // Unlike `_.sortedIndexOf`, this function returns the array at which an - // element *should* be inserted, not where it actually is. _.sortedIndex = function(array, obj, iterator) { iterator = iterator || _.identity; var low = 0, high = array.length; @@ -266,14 +264,6 @@ return low; }; - // Similar to native `indexOf`, but assumes that the array being searched - // is already sorted, giving much faster performance on large arrays. - // Not to be confused with `_.sortedIndex`. - _.sortedIndexOf = function(array, obj) { - var i = _.sortedIndex(array, obj); - return array[i] === obj ? i : -1; - }; - // Safely convert anything iterable into a real, live array. _.toArray = function(iterable) { if (!iterable) return []; @@ -366,8 +356,14 @@ // we need this function. Return the position of the first occurrence of an // item in an array, or -1 if the item is not included in the array. // Delegates to **ECMAScript 5**'s native `indexOf` if available. - _.indexOf = function(array, item) { + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { if (array == null) return -1; + if (isSorted) { + var i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; return -1;