Problem overview
The method count receives an array of numbers, nums, and a number, value. It returns how many times value appears in the array. For nums = [1, 4, 2, 2, 5, 2] and value = 2 the answer is 3, because 2 sits at three positions.
The task is to write the loop yourself, without a built-in helper such as filter, so the lesson practises the basic counting pattern.
Approach: look at every element once
Nothing about the array lets you skip elements, so the method has to look at each one. Keep a counter that starts at 0. For every element, compare it with value, and add 1 to the counter when they are equal. After the last element, the counter is the answer.
It's the same accumulator pattern used for sums and products, with one change: the counter grows by 1 only on a match, so the update sits inside an if.
Step by step
- Declare
answerand set it to 0. It must exist before the loop, so it keeps its value from one pass to the next. TypeScript infers the typenumberfrom the0, so no annotation is needed. - Loop over the elements with
for...of. The variablenumtakes each element's value in turn.for...ofgives the values;for...inwould give the indices as strings, which is not what this method needs. - Compare with
===. Inside the loop, anifchecksnum === valueand incrementsanswerwith++on a match. The strict operator===never converts types:2 === "2"isfalse, while2 == "2"istrue. - Return
answerafter the loop. Areturninside the loop would stop at the first element, and the method would never count more than one.
The solution in TypeScript
class Solution {
count(nums: number[], value: number): number {
let answer = 0;
for (let num of nums) {
if (num === value) {
answer++;
}
}
return answer;
}
}
Notes on the TypeScript details:
- Inferred types.
let answer = 0;has no annotation, but the compiler gives it the typenumber. Annotations and inferred types alike vanish when the code is compiled to JavaScript. letorconstfornum. The solution declaresnumwithlet, which works. Since the loop never reassignsnum,constwould also work and is the more common choice.- Types are checked at compile time only. Calling
count(["2", "2"], 2)is reported by the compiler as a type error. The JavaScript still runs, and since"2" === 2is false, it returns0. Data that comes from outside the program, such as parsed JSON, is not checked by the annotations at all. answer++is shorthand foranswer = answer + 1.
Complexity
Time: O(n), where n is the length of nums. The loop makes one comparison per element.
Space: O(1). Only the counter and the loop variable are stored.
Edge cases and common mistakes
- The value is not in the array. The counter is never incremented and the method returns
0. - An empty array. The loop body never runs, and the answer is
0. - Every element matches. For
[7, 7, 7]and7the answer is3. - Returning inside the loop. It ends the method after one element. The return belongs after the loop.
- Declaring the counter inside the loop. It would reset on every pass, so the method would return at most 1.
- Using
=in the condition.if (num = value)assigns instead of comparing. Equality needs===. NaN.NaN === NaNisfalse, socount([NaN, NaN], NaN)returns0. The lesson's tests use ordinary integers, but it shows that===follows the rules of floating-point numbers.
Testing
count([1, 4, 2, 2, 5, 2], 2)gives3.count([1, 4, 2, 2, 5, 2], 3)gives0.count([], 1)gives0.count([7, 7, 7], 7)gives3.