Start learning free

LESSON 237 OF 673 · SETS

Only in the First List in Python: Set Difference by Hand

Practice Read the full explanation

You get two lists of integers, a and b.

Return a new list 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 list.

 

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

    PYTHON · SETS

    Only In First in Python, explained

    Problem overview

    The method onlyInFirst receives two lists of integers, a and b. It returns a new list with the values of a that are not in b. Each value appears in the result once, in the order it first appears in a. If every value of a is also in b, the result is an empty list.

    For a = [1, 2, 3, 4] and b = [2, 4] the answer is [1, 3]. For a = [5, 6, 5, 7] and b = [7] it 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] the answer is [].

    Approach

    Two questions are asked about every value of a: is it in b, and is it already in the result? Both are "is this value there?" questions, so both are best answered by sets.

    • setB = set(b) turns b into a set. Repeats in b collapse, and each check is fast.
    • seen holds the values already put in the result, so a later copy of the same value is skipped.
    • A list result collects the answer in order, because sets do not keep order.

    Step by step

    1. Build setB = set(b).
    2. Create an empty set seen = set().
    3. Create an empty list result = [].
    4. Loop with for num in a. Reading a from left to right gives the order the task wants.
    5. Test num not in setB and num not in seen: both must hold.
    6. Inside the test, append num to result.
    7. Also add num to seen.
    8. After the loop, return result.

    The solution in Python

    class Solution:
        def onlyInFirst(self, a: List[int], b: List[int]) -> List[int]:
            setB = set(b)
            seen = set()
            result = []
            for num in a:
                if num not in setB and num not in seen:
                    result.append(num)
                    seen.add(num)
            return result

    The condition reads as two checks joined by and. For a = [5, 6, 5, 7] and b = [7], the first 5 passes both checks and is stored. The 6 does too. The second 5 fails the second check, since 5 is in seen. The 7 fails the first check. The result is [5, 6].

    When nothing passes, result is still [], which is the right answer.

    Why two sets

    The two sets answer different questions, and mixing them up is the usual stumble. setB never changes after it is built: it is a fixed picture of b. seen grows while the loop runs: it is a picture of the result so far. A value is kept only when it is absent from the first picture and from the second. Checking membership in a set takes about the same time whether it holds ten values or ten thousand, whereas checking a list means looking at each value in turn, so with sets the work grows in step with the lengths of the two lists, not with their product.

    Why not a one-line comprehension

    A comprehension such as [x for x in a if x not in setB] removes the values in b, but keeps repeats: for [5, 6, 5, 7] and [7] it gives [5, 6, 5]. The seen set is what enforces "each value once".

    Edge cases

    Repeats in b are harmless: the set keeps one copy of each. Negative numbers and zero are ordinary values. If a and b hold exactly the same values, the loop never appends anything and the method returns an empty list. Values that appear in b but not in a never matter, because the loop only reads a.

    Testing

    abresult
    [1, 2, 3, 4][2, 4][1, 3]
    [5, 6, 5, 7][7][5, 6]
    [1, 2][2, 3, 1][]

    Common mistakes

    • Testing num not in b with the list. It works, but walks through b for every value of a. The set makes each check fast.
    • Skipping seen. Repeats in a then repeat in the result.
    • Joining the checks with or. A value would be kept if either check passed, so values from b would slip through.
    • Using set subtraction alone. set(a) - set(b) has the right values, but no promised order.
    Keep going with Python500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free