Skip to content

Stable Partition

Partition an array while preserving the relative order of elements inside each group.

Stable partition rearranges an array so that elements satisfying a predicate appear before the others, while preserving relative order inside both groups.

You use it when grouping is required but original order still carries meaning.

Problem

Given an array AA of length nn and a predicate P(x)P(x), reorder the array so that:

  • all elements satisfying PP appear first
  • all elements not satisfying PP appear after them
  • relative order inside each group is preserved

Algorithm

Use two temporary arrays. Store matching elements in one array and non-matching elements in another, then concatenate them.

stable_partition(A, P):
    yes = empty array
    no = empty array

    for x in A:
        if P(x):
            append x to yes
        else:
            append x to no

    k = 0
    for x in yes:
        A[k] = x
        k += 1

    for x in no:
        A[k] = x
        k += 1

    return length(yes)

Example

Let

A=[8,3,5,2,1,4] A = [8, 3, 5, 2, 1, 4]

Partition by even numbers:

P(x):xmod2=0 P(x): x \bmod 2 = 0
passelementgroup
18yes
23no
35no
42yes
51no
64yes

The stable groups are:

yes=[8,2,4] yes = [8, 2, 4]

and

no=[3,5,1] no = [3, 5, 1]

Final array:

[8,2,4,3,5,1] [8, 2, 4, 3, 5, 1]

Return partition index 33.

Correctness

The algorithm scans elements from left to right. Each element that satisfies PP is appended to yes in its original order. Each remaining element is appended to no in its original order.

Writing all elements from yes before all elements from no produces a valid partition, and each group keeps the same relative order as in the input.

Complexity

operationtime
scan inputO(n)O(n)
write outputO(n)O(n)
totalO(n)O(n)

Space usage:

O(n) O(n)

An in-place stable partition is possible, but it is more complex and often slower in practice.

When to Use

Stable partition is appropriate when:

  • elements must be grouped by a predicate
  • relative order matters
  • extra memory is acceptable
  • predictable linear behavior is preferred

It is less suitable when memory must remain constant and stability is not required.

Implementation

def stable_partition(a, predicate):
    yes = []
    no = []

    for x in a:
        if predicate(x):
            yes.append(x)
        else:
            no.append(x)

    k = 0
    for x in yes:
        a[k] = x
        k += 1

    for x in no:
        a[k] = x
        k += 1

    return len(yes)
func StablePartition[T any](a []T, pred func(T) bool) int {
    yes := make([]T, 0)
    no := make([]T, 0)

    for _, x := range a {
        if pred(x) {
            yes = append(yes, x)
        } else {
            no = append(no, x)
        }
    }

    k := 0
    for _, x := range yes {
        a[k] = x
        k++
    }

    for _, x := range no {
        a[k] = x
        k++
    }

    return len(yes)
}