Reduce Into

ID

swift.reduce_into

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Efficiency

Language

Swift

Tags

efficiency, idiomatic

Description

Reports a .reduce(initial, { …​ .append(x) …​ }) chain that mutates an accumulator captured by value. Swift offers reduce(into:), which passes the accumulator as inout and avoids the copy-on-write copies that the closure-by-value form triggers on every iteration.

xs.reduce([Int]()) { acc, x in            // FLAW
    var acc = acc
    acc.append(x * 2)
    return acc
}

xs.reduce(into: [Int]()) { acc, x in      // OK
    acc.append(x * 2)
}

Rationale

Sequence.reduce(::) takes the accumulator by value. When the accumulator is a collection (Array, Set, Dictionary, …​), every iteration starts by making a fresh mutable copy and ends by returning the new value, so the cost of the loop is O(n * size-of-accumulator). Sequence.reduce(into:_:) passes the accumulator as inout, so the storage is reused in place and the body of the closure can mutate it directly. The asymptotic cost drops back to O(n).

The rule fires only when the second reduce argument is a closure whose body contains a .append(…​) or .insert(…​) call — that heuristic catches the common collection-building pattern without flagging arithmetic reductions like .reduce(0, +).

Remediation

let doubled = xs.reduce(into: [Int]()) { acc, x in
    acc.append(x * 2)
}

let counts = words.reduce(into: [String: Int]()) { acc, w in
    acc[w, default: 0] += 1
}