Как подсчитать количество определенного элемента в массиве?



Если у меня есть массив [1, 2, 3, 5, 2, 8, 9, 2], Я хотел бы проверить, сколько 2s есть в массиве. Какой самый элегантный способ сделать это в JavaScript без цикла с for петли?

489   12  

12 ответов:

очень просто:

var count = 0;
for(var i = 0; i < array.length; ++i){
    if(array[i] == 2)
        count++;
}

[этот ответ немного устарел: прочитайте правки]

поздоровайтесь с друзьями:map и filter и reduce и forEach и every etc.

(я только иногда пишу 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

    Ничего не найдено.