Вот реализация JavaScript 1.6 Array.indexOf
:
if (!Array.indexOf) {
Array.indexOf = [].indexOf ?
function(arr, obj, from) {
return arr.indexOf(obj, from);
} :
function(arr, obj, from) { // (for IE6)
var l = arr.length,
i = from ? parseInt((1 * from) + (from < 0 ? l : 0), 10) : 0;
i = i < 0 ? 0 : i;
for (; i < l; i++) {
if (i in arr && arr[i] === obj) {
return i;
}
}
return -1;
};
}
Можно использовать набор, в котором есть метод " ( ) " :
function contains(arr, obj) {
var proxy = new Set(arr);
if (proxy.has(obj))
return true;
else
return false;
}
var arr = ['Happy', 'New', 'Year'];
console.log(contains(arr, 'Happy'));
function inArray(elem,array)
{
var len = array.length;
for(var i = 0 ; i < len;i++)
{
if(array[i] == elem){return i;}
}
return -1;
}
Возвращает индекс массива, если найден, или -1, если не найден
function contains(a, obj) {
return a.some(function(element){return element == obj;})
}
Array.prototype.some () был добавлен в ECMA -262 стандарт в 5-м издании
Если вы используете JavaScript 1.6 или новее (Firefox 1.5 или новее), вы можете использовать Array.indexOf. В противном случае, я думаю, вы получите что-то похожее на ваш оригинальный код.
Мы используем этот фрагмент (работает с объектами, массивами, строками):
/*
* @function
* @name Object.prototype.inArray
* @description Extend Object prototype within inArray function
*
* @param {mix} needle - Search-able needle
* @param {bool} searchInKey - Search needle in keys?
*
*/
Object.defineProperty(Object.prototype, 'inArray',{
value: function(needle, searchInKey){
var object = this;
if( Object.prototype.toString.call(needle) === '[object Object]' ||
Object.prototype.toString.call(needle) === '[object Array]'){
needle = JSON.stringify(needle);
}
return Object.keys(object).some(function(key){
var value = object[key];
if( Object.prototype.toString.call(value) === '[object Object]' ||
Object.prototype.toString.call(value) === '[object Array]'){
value = JSON.stringify(value);
}
if(searchInKey){
if(value === needle || key === needle){
return true;
}
}else{
if(value === needle){
return true;
}
}
});
},
writable: true,
configurable: true,
enumerable: false
});
< Сильный > Применение:
var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first"); //true
a.inArray("foo"); //false
a.inArray("foo", true); //true - search by keys
a.inArray({three: "third"}); //true
var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one"); //true
b.inArray('foo'); //false
b.inArray({foo: 'val'}) //true
b.inArray("{foo: 'val'}") //false
var c = "String";
c.inArray("S"); //true
c.inArray("s"); //false
c.inArray("2", true); //true
c.inArray("20", true); //false
У ECMAScript 6 есть элегантное предложение по поиску.
Метод find выполняет функцию обратного вызова один раз для каждого элемента, присутствующего в массиве, пока не найдет элемент, в котором callback возвращает истинное значение. Если такой элемент найден, find немедленно возвращает значение этого элемента. В противном случае поиск возвращает неопределенный. обратный вызов вызывается только для индексов массива, которым присвоены значения; он не вызывается для индексов, которые были удалены или которым никогда не назначались значения.
Вот документация по MDN по этому вопросу. ,
Функциональность поиска работает следующим образом.
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) return false;
}
return (element > 1);
}
console.log( [4, 6, 8, 12].find(isPrime) ); // Undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5
Вы можете использовать это в ECMAScript 5 и ниже с помощью определение функции.
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
enumerable: false,
configurable: true,
writable: true,
value: 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++) {
if (i in list) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return value;
}
}
}
return undefined;
}
});
}
Если вы неоднократно проверяете наличие объекта в массиве, возможно, вам стоит
- Постоянно сортируйте массив, выполняя сортировку вставками в вашем массиве (добавьте новые объекты на нужное место)
- Сделать обновление объектов как удаление + сортировка операции вставки и
- Используйте бинарный поиск в своем
contains(a, obj)
поиске.
ОК, вы можете просто оптимизировать свой код, чтобы получить результат!
Есть много способов сделать это, которые будут чище и лучше, но я просто хотел получить ваш шаблон и применить к нему, используя JSON.stringify
, просто сделайте что-то подобное в вашем случае:
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (JSON.stringify(a[i]) === JSON.stringify(obj)) {
return true;
}
}
return false;
}
Хотя array.indexOf(x)!=-1
является наиболее кратким способом сделать это (и поддерживается браузерами не Internet Explorer более десяти лет ...), это не O (1), а скорее O (N), что ужасно. Если ваш массив не изменится, вы можете преобразовать его в хеш-таблицу, затем выполните table[x]!==undefined
или ===undefined
:
Array.prototype.toTable = function() {
var t = {};
this.forEach(function(x){t[x]=true});
return t;
}
Демо-версия :
var toRemove = [2,4].toTable();
[1,2,3,4,5].filter(function(x){return toRemove[x]===undefined})
(К сожалению, хотя вы можете создать Array.prototype.contains для «замораживания» массива и сохранения хеш-таблицы в this._cache в две строки, это приведет к неверным результатам, если вы решите редактировать свой массив позже. У JavaScript недостаточно хуков для позвольте вам сохранить это состояние, в отличие от Python, например.)
Расширение объекта JavaScript Array
- очень плохая идея, потому что вы вводите новые свойства (ваши пользовательские методы) в циклы for-in
, которые могут нарушать существующие сценарии. Несколько лет назад авторам библиотеки прототипов пришлось реорганизовать реализацию своей библиотеки, чтобы удалить только такого рода вещи.
Если вам не нужно беспокоиться о совместимости с другим JavaScript, работающим на вашей странице, воспользуйтесь этим, в противном случае я бы порекомендовал более неловкое, но более безопасное автономное функциональное решение.
Обновление с 2019 года. Этот ответ с 2008 года (11 лет!) не имеет отношения к современному использованию JS. Обещанное улучшение производительности было основано на тесте, сделанном в браузерах того времени. Это может не относиться к современным контекстам выполнения JS. Если вам нужно простое решение, поищите другие ответы. Если вам нужна лучшая производительность, оцените себя в соответствующих средах исполнения.
Как уже говорили другие, итерация по массиву, вероятно, является наилучшим способом, но он доказан что убывающий цикл while
является самым быстрым способом итерации в JavaScript. Поэтому вы можете переписать свой код следующим образом:
function contains(a, obj) {
var i = a.length;
while (i--) {
if (a[i] === obj) {
return true;
}
}
return false;
}
Конечно, вы можете также расширить прототип Array:
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
И теперь вы можете просто использовать следующее:
alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
Простое решение для этого требования использует find()
Если у вас есть массив объектов, как показано ниже,
var users = [{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "admin"},
{id: "105", name: "user"}];
Затем вы можете проверить, присутствует ли объект с вашим значением или нет
let data = users.find(object => object['id'] === '104');
Если data имеет значение null, то нет администратора, иначе он вернет существующий объект, как показано ниже.
{id: "104", name: "admin"}
Затем вы можете найти индекс этого объекта в массиве и заменить объект, используя приведенный ниже код.
let indexToUpdate = users.indexOf(data);
let newObject = {id: "104", name: "customer"};
users[indexToUpdate] = newObject;//your new object
console.log(users);
Вы получите значение, как показано ниже
[{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "customer"},
{id: "105", name: "user"}];
Надеюсь, это кому-нибудь поможет.
function countArray(originalArray) {
var compressed = [];
// make a copy of the input array
var copyArray = originalArray.slice(0);
// first loop goes over every element
for (var i = 0; i < originalArray.length; i++) {
var count = 0;
// loop over every element in the copy and see if it's the same
for (var w = 0; w < copyArray.length; w++) {
if (originalArray[i] == copyArray[w]) {
// increase amount of times duplicate is found
count++;
// sets item to undefined
delete copyArray[w];
}
}
if (count > 0) {
var a = new Object();
a.value = originalArray[i];
a.count = count;
compressed.push(a);
}
}
return compressed;
};
// It should go something like this:
var testArray = new Array("dog", "dog", "cat", "buffalo", "wolf", "cat", "tiger", "cat");
var newArray = countArray(testArray);
console.log(newArray);
Производительность
Сегодня 2020.01.07 я выполняю тесты на MacO HighSierra 10.13.6 на Chrome v78.0.0, Safari v13.0.4 и Firefox v71.0.0 для 15 выбранных решений. Выводы
- решения, основанные на
JSON
,Set
и на удивлениеfind
(K, N, O), являются самыми медленными во всех браузерах - es6
includes
(F) быстр только на Chrome - Решения, основанные на
for
(C, D) иindexOf
(G, H), достаточно быстры во всех браузерах для маленьких и больших массивов, поэтому, вероятно, они являются лучшим выбором для эффективного решения. - решения, где индекс уменьшается во время цикла, (B) медленнее, вероятно, потому что путь Кэш процессора работает.
- Я также запускаю тест для большого массива, когда искомый элемент находился на позиции 66% длины массива, и решения на основе
for
(C, D, E) дают аналогичные результаты (~ 630 операций в секунду - но E на сафари и Firefox был на 10-20% медленнее, чем C и D)
Полученные результаты
Детали
Я выполняю 2 теста: для массива с 10 элементами и для массива с 1 миллионом элементов. В обоих случаях мы помещаем искомый элемент в середину массива.
let log = (name,f) => console.log(`${name}: 3-${f(arr,'s10')} 's7'-${f(arr,'s7')} 6-${f(arr,6)} 's3'-${f(arr,'s3')}`)
let arr = [1,2,3,4,5,'s6','s7','s8','s9','s10'];
//arr = new Array(1000000).fill(123); arr[500000]=7;
function A(a, val) {
var i = -1;
var n = a.length;
while (i++<n) {
if (a[i] === val) {
return true;
}
}
return false;
}
function B(a, val) {
var i = a.length;
while (i--) {
if (a[i] === val) {
return true;
}
}
return false;
}
function C(a, val) {
for (var i = 0; i < a.length; i++) {
if (a[i] === val) return true;
}
return false;
}
function D(a,val)
{
var len = a.length;
for(var i = 0 ; i < len;i++)
{
if(a[i] === val) return true;
}
return false;
}
function E(a, val){
var n = a.length-1;
var t = n/2;
for (var i = 0; i <= t; i++) {
if (a[i] === val || a[n-i] === val) return true;
}
return false;
}
function F(a,val) {
return a.includes(val);
}
function G(a,val) {
return a.indexOf(val)>=0;
}
function H(a,val) {
return !!~a.indexOf(val);
}
function I(a, val) {
return a.findIndex(x=> x==val)>=0;
}
function J(a,val) {
return a.some(x=> x===val);
}
function K(a, val) {
const s = JSON.stringify(val);
return a.some(x => JSON.stringify(x) === s);
}
function L(a,val) {
return !a.every(x=> x!==val);
}
function M(a, val) {
return !!a.find(x=> x==val);
}
function N(a,val) {
return a.filter(x=>x===val).length > 0;
}
function O(a, val) {
return new Set(a).has(val);
}
log('A',A);
log('B',B);
log('C',C);
log('D',D);
log('E',E);
log('F',F);
log('G',G);
log('H',H);
log('I',I);
log('J',J);
log('K',K);
log('L',L);
log('M',M);
log('N',N);
log('O',O);
This shippet only presents functions used in performance tests - it not perform tests itself!
Массив маленький - 10 элементов
Вы можете выполнять тесты на своем компьютере ЗДЕСЬ
Массив большой - 1.000.000 элементов
Вы можете выполнять тесты на своем компьютере ЗДЕСЬ
Один лайнер:
function contains(arr, x) {
return arr.filter(function(elem) { return elem == x }).length > 0;
}
Я использую следующее:
Array.prototype.contains = function (v) {
return this.indexOf(v) > -1;
}
var a = [ 'foo', 'bar' ];
a.contains('foo'); // true
a.contains('fox'); // false