Skip to content

S2Q1 · Remove K Consecutive Duplicates

⚡ Quick Reference

Function: remove_k_consecutive_duplicates(nums: list, k: int) -> list

Core idea: group consecutive identical elements using itertools.groupby, keep only groups with fewer than k elements.

from itertools import groupby

def remove_k_consecutive_duplicates(nums: list, k: int) -> list:
    result = []
    for val, group in groupby(nums):
        items = list(group)
        if len(items) < k:
            result.extend(items)
    return result

Key rules: - Groups of < k consecutive identical elements are kept - Groups of >= k consecutive identical elements are removed entirely - Non-consecutive duplicates are treated as separate groups


Problem Statement

Problem

Write a function remove_k_consecutive_duplicates(nums, k) that removes all elements belonging to a consecutive run of length >= k. Elements in shorter runs are kept.

Example:

Input
nums=[1, 1, 1, 2, 2, 3, 3, 3, 3], k=3
Output
[2, 2]

Understanding the problem

Group consecutive identical elements:

[1, 1, 1, 2, 2, 3, 3, 3, 3]
 ↑──────↑  ↑───↑  ↑────────↑
  run=3     run=2   run=4

k=3: keep runs with length < 3

run of 1 (len=3): 3 >= 3 → REMOVE
run of 2 (len=2): 2 < 3  → KEEP → [2, 2]
run of 3 (len=4): 4 >= 3 → REMOVE

Result: [2, 2] ✓

itertools.groupby groups consecutive identical elements

groupby(nums) yields (value, group_iterator) pairs for each consecutive run. list(group) collects the run into a list whose length can be checked against k.


Tracing the example

nums = [1, 1, 1, 2, 2, 3, 3, 3, 3], k = 3

val items len(items) < k? Added to result
1 [1,1,1] 3 -
2 [2,2] 2 [2, 2]
3 [3,3,3,3] 4 -

Result: [2, 2]


More examples to build intuition

remove_k_consecutive_duplicates([1, 1, 2, 2, 2, 3], 3)
# groups: [1,1](2), [2,2,2](3), [3](1)
# keep: len<3 → [1,1] and [3]
# → [1, 1, 3]

remove_k_consecutive_duplicates([5, 5, 5, 5], 2)
# one group: [5,5,5,5](4), 4 >= 2 → remove all
# → []

remove_k_consecutive_duplicates([1, 2, 1, 2], 2)
# groups: [1](1), [2](1), [1](1), [2](1) - all length 1
# 1 < 2 → all kept
# → [1, 2, 1, 2]

The last example shows that non-consecutive duplicates are treated as separate groups.


Solution approaches

from itertools import groupby

def remove_k_consecutive_duplicates(nums: list, k: int) -> list:
    result = []
    for val, group in groupby(nums):
        items = list(group)
        if len(items) < k:
            result.extend(items)
    return result
def remove_k_consecutive_duplicates(nums: list, k: int) -> list:
    if not nums:
        return []
    result = []
    count  = 1

    for i in range(1, len(nums)):
        if nums[i] == nums[i - 1]:
            count += 1
        else:
            if count < k:
                result.extend([nums[i - 1]] * count)
            count = 1

    # Handle the last group
    if count < k:
        result.extend([nums[-1]] * count)

    return result

Count each run manually. When a value changes (or we reach the end), decide whether to keep the run.

from itertools import groupby

def remove_k_consecutive_duplicates(nums: list, k: int) -> list:
    return [
        val
        for val, group in groupby(nums)
        for val in list(group)
        if len(list(group)) < k   # ⚠️ groupby iterator is consumed - use manual approach
    ]

groupby iterator can only be consumed once

The pattern above has a bug - list(group) consumes the iterator the first time, making len(list(group)) return 0 on the second call. Always convert to a list first and reuse it.

Correct version:

from itertools import groupby

def remove_k_consecutive_duplicates(nums: list, k: int) -> list:
    groups = [(val, list(g)) for val, g in groupby(nums)]
    return [v for val, items in groups if len(items) < k for v in items]
from itertools import groupby

def remove_k_consecutive_duplicates(nums: list, k: int) -> list:
    groups = [(val, list(g)) for val, g in groupby(nums)]
    kept   = filter(lambda vg: len(vg[1]) < k, groups)
    return [v for _, items in kept for v in items]

filter(lambda vg: len(vg[1]) < k, groups) keeps only groups shorter than k. The final comprehension flattens them back into a list.


Key takeaways

01

itertools.groupby for consecutive runs

groupby(nums) splits a list into consecutive runs of identical values. It only groups consecutive elements - [1,2,1] gives three groups, not two.

02

Convert groupby iterator to list immediately

The group iterator from groupby can only be consumed once. Always do items = list(group) and reuse items - calling list(group) twice returns an empty list the second time.

03

extend() to add all items of a run

result.extend(items) adds all elements of the kept run to the result. Using append(items) would add the list as a single element - use extend to flatten.