Problem overview
PositiveSquares gets a List<int> named nums and returns a new List<int> holding the square of every number above 0, in the order of nums. Zero and negative numbers are left out. For [3, -1, 0, 4] the result is [9, 16]. If nothing is above 0, as in [-5, -2, 0], the result is an empty list. The input may itself be empty.
Approach: filter, then transform
Two LINQ methods cover the two jobs, and the order matters:
Where(num => num > 0)keeps the numbers for which the lambda returnstrue. Items that fail are dropped.Select(num => num * num)replaces each remaining number with its square.
The filter must come first. A square is never negative, so squaring first loses the information the filter needs: -3 becomes 9 and then passes > 0. With [3, -1, 0, 4], squaring first and then filtering gives [9, 1, 16], which wrongly includes the square of -1.
Step by step
- Chain the calls on
nums:Whereto keep the numbers above 0,Selectto square them, andToList()to get aList<int>. Store it insquares. - Return
squares. When nothing passes the filter, the list is just empty, which is the right answer.
The solution in C#
class Solution {
public List<int> PositiveSquares(List<int> nums) {
List<int> squares = nums.Where(num => num > 0).Select(num => num * num).ToList();
return squares;
}
}
Each lambda has its own num. They are separate parameters, so using the same name twice is fine.
Details that matter
- Zero is excluded. The test is
> 0, not>= 0. Zero is not above 0, and its square would be a stray0in the result. - Order is kept. Both
WhereandSelectprocess items in their original order. - No overflow here. Numbers are between -1000 and 1000, so a square is at most 1,000,000. An
intholds more than two billion. With much larger inputs,num * numwould silently wrap around. - An empty result is a list, not
null.ToList()always gives a list, even with no items.
The same thing with a loop
A foreach loop does the filter and the transform in one pass:
List<int> squares = new List<int>();
foreach (int num in nums) {
if (num > 0) {
squares.Add(num * num);
}
}
return squares;
For [3, -1, 0, 4] it returns [9, 16]. The if is the Where, and the expression inside Add is the Select. In the loop version, the order of the two jobs is built into the code: the test looks at num, and only then is the square computed. The LINQ chain says the same thing in a line, and you read it left to right, as "keep the positives, then square them".
Pick whichever form you find clearer. The lesson uses the chain because it separates the two ideas, "which numbers" and "what to do with them".
Testing
Outputs from running the solution:
| nums | Result |
|---|---|
[3, -1, 0, 4] | [9, 16] |
[-5, -2, 0] | [] |
[1, 2, 3] | [1, 4, 9] |
[] | [] |
Common mistakes
- Filtering with the wrong test. Writing
num != 0keeps the negative numbers, andnum >= 0keeps zero. The lesson asks for numbers strictly above 0. SelectbeforeWhere. As shown above, the squares of negative numbers sneak in.- Using
Math.Pow. It returns adouble, so it needs a cast back toint. For a simple square,num * numis shorter and exact. - Forgetting
ToList(). The method returns aList<int>.
