Подсчет определенных элементов массива в JavaScript

Представляя метод .filter, который можно использовать буквально для фильтрации элементов массива на основе условия, мы можем использовать его в дополнение к свойству .length для подсчета определенных элементов массива. Условие метода .filter задается функцией, передаваемой в качестве параметра. Также мы представим метод .reduce, который выполняет функцию для каждого элемента массива и возвращает одно значение.

Функция, передаваемая в качестве параметра, может быть как стрелочной функцией, так и обычной функцией обратного вызова, и она будет определять, какие элементы .filter будет добавлять или не добавлять в возвращаемый массив или что именно будет делать метод .reduce для каждого элемента массива.

Подсчет определенных элементов массива в JavaScript с помощью метода .filter

.filter — это метод сущности Array, который возвращает новый массив, отфильтрованный по заданному условию. Возвращение нового массива означает, что исходный массив, для которого вызывается метод, будет неизменным. Например, если мы хотим получить в массиве все элементы, равные значению ‘one’, мы можем использовать .filter, как показано ниже:

// Input
let array = ['one', 'two', 'three', 'four', 'five']
array = array.filter(element => element == 'one')
console.log(array)
Войти в полноэкранный режим Выйти из полноэкранного режима

Выход:

// Output
[ 'one' ]
Войти в полноэкранный режим Выйти из полноэкранного режима

Как и ожидалось, метод .filter возвращает массив на основе условия element == 'one'. Таким образом, если фактический элемент массива равен 'one', то фильтр добавит этот элемент в возвращаемый массив.

Но что происходит внутри метода .filter? Мы можем увидеть это лучше, используя общую структуру функции condition():

// Input
let array = ['one', 'two', 'three', 'four', 'five']
array = array.filter(function condition(element) {
    if (element == 'one') return true
    return false
})
console.log(array)
Вход в полноэкранный режим Выход из полноэкранного режима

Таким образом, мы получим тот же результат, что и в первом примере:

// Output
[ 'one' ]
Вход в полноэкранный режим Выход из полноэкранного режима

Функция condition() получает элемент в качестве параметра, и если этот элемент равен определенному значению, в данном случае 'one', она возвращает true, а если нет, возвращает false. Таким образом, метод .filter добавляет любой из элементов, для которого условие приводит к true; поскольку в исходном массиве только первый элемент one, .filter возвращает только один элемент.

Обратите внимание, что функция condition() объявляется внутри метода .filter. Если вы объявите ее снаружи и вызовете внутри .filter, она не будет работать, потому что element является частью области обратного вызова.

По сути, функция обратного вызова — это функция, передаваемая в качестве параметра другой функции, которая называется «внешней функцией». Функция обратного вызова будет вызвана внешней функцией, чтобы сделать что-то; в случае метода .filter, она вызовет функцию обратного вызова condition() для фильтрации массива на основе его условия.

Возвращаясь к нашей цели, .filter в итоге вернет новый массив с элементами array.length, каждый из которых является элементом, которому функция обратного вызова вернула значение, равное true. Поскольку мы хотим подсчитать эти отфильтрованные элементы, мы можем легко сделать это с помощью свойства .length.

.length — это свойство сущности Array, которое возвращает количество элементов в массиве. Это число всегда больше самого высокого индекса в этом массиве, потому что первый элемент всегда находится на индексе, равном 0.

// Input
let array = [1, 2, 3, 4, 5]
console.log(array.length)
Войти в полноэкранный режим Выход из полноэкранного режима

Выход:

// Output
5
Войти в полноэкранный режим Выход из полноэкранного режима

Количество элементов в массиве array равно 5. 5 — это число больше, чем индекс значения 5, то есть 4.

Сложив все вместе, в качестве примера мы можем использовать следующее: Как получить количество всех контрольных работ в школе, которые больше семи? Массив тестовых отметок находится в примере.

// Input
let notes = [7.0, 6.7, 7.3, 9.8, 5.6, 7.1, 7.8, 6.2, 8.0, 9.0, 4.5, 6.9, 7.5, 8.5, 6.4]
greaterThanSeven = notes.filter(value => value > 7)
console.log(greaterThanSeven.length)
Войти в полноэкранный режим Выход из полноэкранного режима

Выход:

// Output (The array returned by the .filter is: [7.3, 9.8, 7.1, 7.8, 8, 9, 7.5, 8.5])
8
Войти в полноэкранный режим Выйти из полноэкранного режима

Итак, 8 — это количество нот, которые больше 7 из всех 15 нот в исходном массиве notes.

Теперь, в качестве другого варианта, мы можем использовать метод сущности массива .reduce. Этот метод используется для выполнения функции обратного вызова (как и .filter) на каждом элементе массива, но в итоге возвращает одно значение.

Простым примером работы .reduce является сумма всех элементов массива:

// Input
let array = [1, 2, 3, 4, 5].reduce((previous, current) => previous + current)
console.log(array)
Войти в полноэкранный режим Выход из полноэкранного режима

Выход:

// Output
15
Войти в полноэкранный режим Выход из полноэкранного режима

Но этот метод можно использовать и по-другому, то есть передавая начальное значение. В предыдущем примере мы видим, что previous начинается с первого индексного элемента в массиве, являясь функцией обратного вызова, таким образом:

/*
previous + current = result
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
10 + 5 = 15 -> final result
*/
Войти в полноэкранный режим Выйти из полноэкранного режима

Эта сумма работает правильно, потому что если мы не передадим второй параметр (так как функция обратного вызова является первым параметром) методу .reduce, он будет считать previous первым элементом массива в первой итерации.

Но если мы хотим посчитать определенные элементы в массиве? Мы не можем использовать первый элемент в качестве previous, потому что это может привести к неправильному значению. В приведенном ниже примере подсчитывается количество чисел 2 в массиве:

// Input
let array = [1, 2, 3, 4, 5].reduce((sum, value) => (value == 2 ? sum + 1 : sum))
console.log(array)
Войдите в полноэкранный режим Выход из полноэкранного режима

Выход:

// Output
2
Вход в полноэкранный режим Выход из полноэкранного режима

Как мы видим, результатом является 2, но правильный ответ — 1. Это произошло потому, что sum инициализируется первым элементом 1, так как мы не передали никаких других параметров, кроме функции обратного вызова. Чтобы выполнить коррекцию, мы можем просто передать 0 в качестве второго параметра .reduce:

// Input
let array = [1, 2, 3, 4, 5].reduce((sum, value) => (value == 2 ? sum + 1 : sum), 0)
console.log(array)
Войти в полноэкранный режим Выйти из полноэкранного режима

Выход:

// Output
1
Войти в полноэкранный режим Выйти из полноэкранного режима

Таким образом, .reduce делает sum + 1 каждый раз, когда текущий элемент равен 2, при этом sum инициализируется 0.

Дополнительно

Кроме того, вместо того, чтобы использовать все эти логики каждый раз, когда нам нужно подсчитать определенные элементы в массиве, мы можем использовать свойство сущности .prototype Array, чтобы написать пользовательские методы или свойства для этой сущности.

Чтобы сделать метод .countCertainElements для сущности Array, мы можем использовать следующую структуру:

// Input
// Declaring the prototype .countCertainElements method
Array.prototype.countCertainElements = function(value){
    return this.filter(arrayElement => arrayElement == value).length
}
let array1 = [1, 2, 2, 2, 3, 4, 5]
console.log(array1.countCertainElements(2))
Вход в полноэкранный режим Выйти из полноэкранного режима

Выход:

// Output
3
Войти в полноэкранный режим Выход из полноэкранного режима

То же самое можно сделать и для .reduce:

// Input
// Declaring the prototype .countCertainElements method
Array.prototype.countCertainElements = function(value){
    return this.reduce((sum, element) => (element == value ? sum + 1 : sum), 0)
}
let array1 = [1, 2, 2, 2, 3, 4, 5]
console.log(array1.countCertainElements(2))
Вход в полноэкранный режим Выход из полноэкранного режима

Выход:

// Output
3
Войти в полноэкранный режим Выход из полноэкранного режима

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *