Start learning free

LESSON 273 OF 678 · TUPLES, SORTING & BUILT-INS

Positive Squares in Swift: Chaining filter and map

Practice Read the full explanation

You get an array of integers, nums.

Return a new array with the square of every number above 0. A number's square is the number times itself.

Keep the squares in the order of their numbers in nums.

Leave out 0 and the negative numbers. If no number is above 0, return an empty array.

 

Example 1:

Input: nums = [3, -1, 0, 4]
Output: [9, 16]
Explanation: Only 3 and 4 are above 0.
3 times 3 is 9, and 4 times 4 is 16.

Example 2:

Input: nums = [-5, -2, 0]
Output: []
Explanation: No number is above 0.

Example 3:

Input: nums = [1, 2, 3]
Output: [1, 4, 9]
Explanation: Every number is above 0, so every number is squared.

 

Constraints:

  • nums may be empty.
  • Every number is between -1000 and 1000.
STEP 1 OF 2
    Ctrl + Enter to check

    SWIFT · TUPLES, SORTING & BUILT-INS

    Positive Squares in Swift, explained

    Problem overview

    The function positiveSquares receives an array of integers, nums, which may be empty. It returns a new array with the square of every number above 0, in the same order as the numbers in nums. Zero and negative numbers are left out. If nothing is above 0, the result is an empty array.

    For [3, -1, 0, 4] the result is [9, 16]: only 3 and 4 are above 0. For [-5, -2, 0] it is [].

    Approach

    Two things happen to the numbers: some are dropped, and the rest are changed. Swift has a method for each. filter keeps the items for which a closure returns true. map replaces every item with the closure's result. You can chain them, so the output of filter goes straight into map.

    The order matters. Filter first, then square. If you square first, -3 becomes 9, which passes a test for "above 0" and sneaks into the result. For [3, -1, 0, 4], squaring first and then keeping the numbers above 0 gives [9, 1, 16], which is wrong. Zero is not above 0, so the test is > 0, not >= 0.

    You could also write this with a loop: start with an empty array, go through nums, and append num * num when num > 0. The chain says the same thing in one line, and it reads as the two ideas in the statement: keep some numbers, then change them.

    Step by step

    1. Keep the numbers above 0 with nums.filter { $0 > 0 }. For the first example this leaves [3, 4].
    2. Square each one with .map { $0 * $0 } on the filtered array. The result is [9, 16]. Both steps go in one line, in a constant named squares.
    3. Return squares. When no number is above 0, filter gives an empty array, map of an empty array is empty, and that is the right answer.

    The solution in Swift

    class Solution {
        func positiveSquares(_ nums: [Int]) -> [Int] {
            let squares = nums.filter { $0 > 0 }.map { $0 * $0 }
            return squares
        }
    }
    

    Swift details:

    • Each closure has its own $0. In the filter closure, $0 is a number from nums. In the map closure, $0 is a number that passed the filter.
    • The filter closure must return a Bool. { $0 > 0 } does. A closure such as { $0 * 2 } doesn't compile there: the compiler reports that it cannot convert Int to the closure result type Bool.
    • Nothing is modified. filter and map each return a new array, and nums stays as it was.
    • Squares fit in Int. The numbers are between -1000 and 1000, so a square is at most 1,000,000.

    Each step produces a whole array before the next one starts. For [3, -1, 0, 4], the filter gives [3, 4], and the map turns that into [9, 16]. Seeing the middle array helps when a result is wrong: if the filter's output already contains the wrong numbers, the problem is in the first closure, not the second.

    Edge cases and common mistakes

    • An empty array. [] gives [].
    • Only zero and negatives. [-5, -2, 0] gives [].
    • All positive. [1, 2, 3] gives [1, 4, 9].
    • Using >= 0. That would keep 0 and add a 0 to the result.
    • Mapping before filtering. As shown above, nums.map { $0 * $0 }.filter { $0 > 0 } returns [9, 1, 16] for the first example, because the negative number was squared into a positive one.

    Testing

    • [3, -1, 0, 4] gives [9, 16].
    • [-5, -2, 0] gives [].
    • [1, 2, 3] gives [1, 4, 9].
    • [] gives [].
    Keep going with Swift500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free