12 ответов:
[этот ответ немного устарел: прочитайте правки]
поздоровайтесь с друзьями:
mapиfilterиreduceиforEachиeveryetc.(я только иногда пишу for-loops в javascript, из-за отсутствия области видимости на уровне блока, поэтому вам все равно нужно использовать функцию в качестве тела цикла, если вам нужно захватить или клонировать индекс или значение итерации. For-loops более эффективны в целом, но иногда вам нужно закрытие.)
самый читаемый как:
[...].filter(function(x){return x==2}).lengthследующее более эффективно для пространства (O (1), а не O (N)), но я не уверен, сколько выгоды/штрафа вы можете заплатить с точки зрения времени (не более чем постоянный фактор, так как вы посещаете каждый элемент ровно один раз):
[...].reduce(function(total,x){return x==2 ? total+1 : total}, 0)(если вам нужно оптимизировать этот конкретный фрагмент кода, цикл for может быть быстрее в некоторых браузерах... вы можете проверить вещи на jsperf.com.)
вы можете быть элегантной и превратить его в прототип функции:
[1, 2, 3, 5, 2, 8, 9, 2].count(2)такой:
Object.defineProperties(Array.prototype, { count: { value: function(value) { return this.reduce(...); } } });вы также можете придерживаться обычной старой техники for-loop (см. другие ответы) внутри приведенного выше определения свойства (опять же, это, вероятно, будет намного быстрее).
2017 edit:
Упс, этот ответ стал более популярен, чем правильный ответ. на самом деле, просто используйте принятый ответ. Хотя этот ответ может быть симпатичным, компиляторы js, вероятно, не оптимизируют (или не могут из-за спецификации) такие случаи. Так что вы действительно должны написать простой цикл for:
Object.defineProperties(Array.prototype, { count: { value: function(query) { /* Counts number of occurrences of query in array, an integer >= 0 Uses the javascript == notion of equality. */ var count = 0; for(let i=0; i<this.length; i++) if (this[i]==query) count++; return count; } } });вы можете определить версию
.countStrictEq(...), который используется===понятие равенства. Понятие равенства может быть важно для того, что вы делаете! (например,[1,10,3,'10'].count(10)==2, потому что числа, как '4' ==4 в javascript... следовательно, называя его.countEqили.countNonstrictподчеркивает, что он использует==оператора.)также рассмотрите возможность использования собственной структуры данных multiset (например, как python'
collections.Counter'), чтобы избежать необходимости делать подсчет в первую очередь.class Multiset extends Map { constructor(...args) { super(...args); } add(elem) { if (!this.has(elem)) this.set(elem, 1); else this.set(elem, this.get(elem)+1); } remove(elem) { var count = this.has(elem) ? this.get(elem) : 0; if (count>1) { this.set(elem, count-1); } else if (count==1) { this.delete(elem); } else if (count==0) throw `tried to remove element ${elem} of type ${typeof elem} from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)`; // alternatively do nothing {} } }демо:
> counts = new Multiset([['a',1],['b',3]]) Map(2) {"a" => 1, "b" => 3} > counts.add('c') > counts Map(3) {"a" => 1, "b" => 3, "c" => 1} > counts.remove('a') > counts Map(2) {"b" => 3, "c" => 1} > counts.remove('a') Uncaught tried to remove element a of type string from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)sidenote: хотя, если вы все еще хотите функциональный способ программирования (или одноразовый однострочный без переопределения массива.прототип), вы могли бы написать его более кратко в настоящее время как
[...].filter(x => x==2).length. Если вы заботитесь о производительности, обратите внимание, что в то время как это асимптотически такая же производительность, как и для цикла for (o(N) time), он может потребовать O(N) дополнительной памяти (вместо O(1) памяти), потому что он почти наверняка создаст промежуточный массив, а затем подсчитает элементы этого промежуточного массива.
2017: Если кто-то все еще заинтересован в вопросе, мое решение заключается в следующем:
const arrayToCount = [1, 2, 3, 5, 2, 8, 9, 2]; const result = arrayToCount.filter(i => i === 2).length; console.log('number of the found elements: ' + result);
ES6 обновление до JS:
// Let has local scope let array = [1, 2, 3, 5, 2, 8, 9, 2] // Functional filter with an Arrow function array.filter(x => x===2).length // -> 3следующее единогласное функции стрелочку (лямбда-функция) в JS:
(x) => { const k = 2 return k * x }можно упростить эту краткую форму для одного входа:
x => 2 * xздесь
returnподразумевается.
Если вы используете lodash или подчеркиваете _.графби метод предоставит объект совокупных итогов, настроенных по каждому значению в массиве. Вы можете превратить это в один лайнер, если вам нужно только посчитать одно значение:
_.countBy(['foo', 'foo', 'bar'])['foo']; // 2Это также отлично работает на массивах чисел. Один лайнер для вашего примера будет:
_.countBy([1, 2, 3, 5, 2, 8, 9, 2])[2]; // 3
самый странный способ, который я могу придумать, это:
(a.length-(' '+a.join(' ')+' ').split(' '+n+' ').join(' ').match(/ /g).length)+1где:
- a массив
- n это число для подсчета в массиве
мое предложение, использовать while или цикл for ;-)
не используя цикл обычно означает передачу процесса в какой-то метод, который тут использовать цикл.
вот как наш цикл ненавидящий кодер может удовлетворить свое отвращение, по цене:
var a=[1, 2, 3, 5, 2, 8, 9, 2]; alert(String(a).replace(/[^2]+/g,'').length); /* returned value: (Number) 3 */вы также можете повторно вызвать indexOf, если он доступен в качестве метода массива, и перемещать указатель поиска каждый раз.
это не создает новый массив, и цикл быстрее, чем forEach или фильтр.
Это может иметь значение если у вас есть миллион членов посмотреть.
function countItems(arr, what){ var count= 0, i; while((i= arr.indexOf(what, i))!= -1){ ++count; ++i; } return count } countItems(a,2) /* returned value: (Number) 3 */
большинство опубликованных решений, использующих функции массива, такие как фильтр, являются неполными, поскольку они не параметризованы.
здесь идет решение, с которым элемент для подсчета может быть установлен во время выполнения.
function elementsCount(elementToFind, total, number){ return total += number==elementToFind; } var ar = [1, 2, 3, 5, 2, 8, 9, 2]; var elementToFind=2; var result = ar.reduce(elementsCount.bind(this, elementToFind), 0);преимущество этого подхода заключается в том, что можно легко изменить функцию, чтобы подсчитать, например, количество элементов больше X.
вы также можете объявить функцию reduce inline
var ar = [1, 2, 3, 5, 2, 8, 9, 2]; var elementToFind=2; var result = ar.reduce(function (elementToFind, total, number){ return total += number==elementToFind; }.bind(this, elementToFind), 0);
var arrayCount = [1,2,3,2,5,6,2,8]; var co = 0; function findElement(){ arrayCount.find(function(value, index) { if(value == 2) co++; }); console.log( 'found' + ' ' + co + ' element with value 2'); }Я бы сделал что-то вроде этого:
var arrayCount = [1,2,3,4,5,6,7,8]; function countarr(){ var dd = 0; arrayCount.forEach( function(s){ dd++; }); console.log(dd); }
создайте новый метод для класса массива в файле уровня ядра и используйте его по всему проекту.
// say in app.js Array.prototype.occurrence = function(val) { return this.filter(e => e === val).length; }используйте это в любом месте вашего проекта -
[1, 2, 4, 5, 2, 7, 2, 9].occurrence(2); // above line returns 3
решение с помощью рекурсии
function count(arr, value) { if (arr.length === 1) { return arr[0] === value ? 1 : 0; } else { return (arr.shift() === value ? 1 : 0) + count(arr, value); } } count([1,2,2,3,4,5,2], 2); // 3
вы можете использовать свойство length в массиве JavaScript:
var myarray = []; var count = myarray.length;//return 0 myarray = [1,2]; count = myarray.length;//return 2
Comments