Replace Loop with Pipeline
Before you begin: Loops, collections, predicates, and simple lambda expressions.
Replace Loop with Pipeline expresses a collection transformation as stages such as filtering, mapping, and combining. Here a pipeline means that the output of one stage becomes the input of the next. It does not imply threads, network services, or asynchronous execution. 1
Original version: collect doubled positive rewards
A reward list can contain zero and negative adjustments. This operation keeps only positive values and doubles them, preserving their order. Assume small integers without overflow.
public static class Rewards
{
public static int[] Bonuses(int[] amounts)
{
var result = new List<int>();
foreach (int amount in amounts)
{
if (amount > 0) result.Add(amount * 2);
}
return result.ToArray();
}
}def bonuses(amounts):
result = []
for amount in amounts:
if amount > 0:
result.append(amount * 2)
return resultThe loop handles selection, transformation, and storage. It is already reasonable code; the alternative names the first two jobs more directly.
Refactored version: filter, transform, collect
public static class Rewards
{
public static int[] Bonuses(int[] amounts)
{
return amounts
.Where(amount => amount > 0)
.Select(amount => amount * 2)
.ToArray();
}
}Where keeps positive values. Select doubles each retained value. ToArray executes the deferred query and returns a completed array, as the original method did. Omitting that final collection step would change the result type and when the work happens. 2
def bonuses(amounts):
return [amount * 2 for amount in amounts if amount > 0]The list comprehension expresses filtering and transformation in one collection expression. It returns a completed list, not a generator. The if selects an amount before the leading expression doubles it.
For -1, 3, 0, 2, both versions return 6, 4. Nothing sorts the result or processes it in parallel.
Prefer a loop when the loop tells the story better
A transformation with several early exits, complex state, or important side effects may be clearer as an ordinary loop. A long chain of unfamiliar functions can be harder to read than the code it replaces.
Preserve order, number of evaluations, exception timing, and whether the result is eager or lazy. A pipeline over a database query may translate into SQL rather than execute like an in-memory loop. The example’s arrays and lists avoid that additional distinction.
Use the transformation vocabulary when it makes the operation recognizable: filter these values, map them to those values, then collect. Do not substitute compact syntax merely to make the original code look old-fashioned.