Start learning free

LESSON 241 OF 675 · SETS

Only in the First in TypeScript: Difference With Sets

Practice Read the full explanation

You get two arrays of integers, a and b.

Return a new array with the values of a that are not in b.

Each value goes into the result only once. Keep the values in the order they first appear in a.

If every value of a is also in b, return an empty array.

 

Example 1:

Input: a = [1, 2, 3, 4], b = [2, 4]
Output: [1, 3]
Explanation: 2 and 4 are in b, so they are left out.

Example 2:

Input: a = [5, 6, 5, 7], b = [7]
Output: [5, 6]
Explanation: 7 is in b.
5 appears twice in a, but only once in the result.

Example 3:

Input: a = [1, 2], b = [2, 3, 1]
Output: []
Explanation: Both values of a are also in b, so nothing is left.

 

Constraints:

  • a and b each have at least one number.
  • Every number is between -109 and 109.
STEP 1 OF 8
    Ctrl + Enter to check

    TYPESCRIPT · SETS

    Only In First in TypeScript, explained

    Problem overview

    The method onlyInFirst receives two arrays of integers, a and b, and returns a new array with the values of a that are not in b. Each value goes into the result once, and the values keep the order in which they first appear in a. If every value of a is also in b, the result is an empty array.

    For a = [1, 2, 3, 4] and b = [2, 4] the result is [1, 3]. For a = [5, 6, 5, 7] and b = [7] the result is [5, 6]: 7 is in b, and 5 appears twice in a but only once in the result. For a = [1, 2] and b = [2, 3, 1] nothing is left, so the result is [].

    Approach: two sets, one loop

    Each value of a has to pass two tests: b must not contain it, and the result must not contain it yet. Both are "is this value there?" questions, and a Set answers them quickly.

    • A set built from b, called setB, answers the first test. Repeats in b collapse into one entry, which is fine, since only membership matters.
    • A second set, seen, records the values already put in the result. It answers the second test, and it is the same idea that removes repeats from a single array.

    Looping over a from left to right keeps the first-appearance order. The values go into an array, result, because the answer has to be an array.

    Step by step

    1. Build setB with new Set(b), typed Set<number>.
    2. Create an empty seen set of numbers.
    3. Create an empty result array of numbers.
    4. Loop over a with for...of.
    5. Test both conditions with &&: !setB.has(num) and !seen.has(num). The body runs only when both are true.
    6. Push num onto result.
    7. Add num to seen, so that a later copy in a is skipped.
    8. Return result after the loop. It may be empty.

    The solution in TypeScript

    class Solution {
        onlyInFirst(a: number[], b: number[]): number[] {
            let setB: Set<number> = new Set(b);
            let seen: Set<number> = new Set();
            let result: number[] = [];
            for (let num of a) {
                if (!setB.has(num) && !seen.has(num)) {
                    result.push(num);
                    seen.add(num);
                }
            }
            return result;
        }
    }
    

    Notes on the code:

    • Short-circuit &&. If the first test is false, the second is not evaluated. That makes no difference to the answer here, only to how much work is done.
    • The inputs are not changed. The method builds new containers and leaves a and b as they were.

    Another way

    The same result can come from removing repeats first and filtering afterwards:

    function onlyInFirst(a: number[], b: number[]): number[] {
        const setB: Set<number> = new Set(b);
        return [...new Set(a)].filter((num) => !setB.has(num));
    }
    

    On the three examples it returns [1,3], [5,6] and []. new Set(a) drops the repeats of a while keeping first-appearance order, and filter keeps the values that b does not have. The lesson's loop does the same work in one pass and shows each idea separately.

    Edge cases and common mistakes

    • Forgetting seen. Filtering with only the first test, a.filter(n => !setB.has(n)), keeps repeats. For [5, 6, 5, 7] and [7] it returns [5,6,5], not [5,6].
    • Repeats of a value that is not in b. a = [2, 2, 9] with b = [2] gives [9]. Every 2 is excluded by b, however many times it appears.
    • Searching b as an array. b.includes(num) works, but it scans b for every value of a. A set avoids that.
    • Swapping the arrays. The values of b that are missing from a do not matter. The set is built from b, and the loop runs over a.
    • Value types. The sets compare values with exact equality, so the number 1 and the string "1" are different. With the typed arrays of this lesson that cannot arise.

    Testing

    • a = [1, 2, 3, 4], b = [2, 4] gives [1, 3].
    • a = [5, 6, 5, 7], b = [7] gives [5, 6].
    • a = [1, 2], b = [2, 3, 1] gives [].
    • a = [2, 2, 9], b = [2] gives [9].
    Keep going with TypeScript500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free