Представляя метод .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