Tracks
/
Factor
Factor
/
Exercises
/
Belgian Boxcars
Belgian Boxcars

Belgian Boxcars

Learning Exercise

Introduction

Sometimes you need to view a sequence as a series of pieces rather than element-by-element. The grouping, splitting, and splitting.monotonic vocabularies give you four ways to do that.

group — disjoint chunks of size n

group ( seq n -- groups )
USING: grouping ;

{ 1 2 3 4 5 6 7 } 3 group .
! => { { 1 2 3 } { 4 5 6 } { 7 } }

If the sequence length isn't a multiple of n, the final group is shorter than n.

clump — overlapping sliding window of size n

clump ( seq n -- clumps )
USING: grouping ;

{ 1 2 3 4 5 } 2 clump .
! => { { 1 2 } { 2 3 } { 3 4 } { 4 5 } }

If the sequence is shorter than n, the result is empty.

split-when — break wherever a predicate fires

split-when ( seq quot: ( elt -- ? ) -- pieces )
USING: splitting ;

{ 1 2 0 3 4 0 5 } [ zero? ] split-when .
! => { { 1 2 } { 3 4 } { 5 } }

Each element gets its own predicate call; truthy elements are the break points and aren't kept in the result.

monotonic-split — break runs where an adjacent-pair check fails

monotonic-split ( seq quot: ( a b -- ? ) -- pieces )
USING: splitting.monotonic ;

{ 1 1 2 2 2 3 } [ = ] monotonic-split .
! => { { 1 1 } { 2 2 2 } { 3 } }

The predicate runs on adjacent pairs. While it returns truthy, the run continues; when it returns f, a new piece starts. With [ = ] you get runs of equal elements; with [ <= ] you get non-decreasing runs; and so on.

When to reach for which

  • group/clump: you know the size you want.
  • split-when: you know what a break element looks like.
  • monotonic-split: you know what makes two adjacent elements still belong together.

Instructions

It's another busy night at the Antwerp marshalling yard. You're the dispatcher on duty: incoming freight cars need to be regrouped into outbound trains, couplings inspected, routes split at junctions, and identical cargo coalesced for billing.

Each car is a string naming what it's carrying: "coal", "timber", "crates", etc.

1. Couple cars into trains

Define couple to take an array of cars and a length n, and return non-overlapping trains of n cars each. The final train may be shorter if the count doesn't divide evenly.

{ "coal" "coal" "coke" "ore" "ore" "timber" "timber" } 3 couple .
! => { { "coal" "coal" "coke" } { "ore" "ore" "timber" } { "timber" } }

2. Peek at the couplings

Define peek-couplings to take an array of cars and return every adjacent pair, so the inspector can examine each coupling.

{ "coal" "ore" "timber" "crates" } peek-couplings .
! => { { "coal" "ore" } { "ore" "timber" } { "timber" "crates" } }

3. Split the chain at junctions

Define split-at-junctions to take an array of cars and an array of junctions (cars that mark a break point), and return the legs between junction cars. The junction cars themselves aren't kept.

{ "coal" "coal" "switch" "ore" "switch" "timber" }
{ "switch" } split-at-junctions .
! => { { "coal" "coal" } { "ore" } { "timber" } }

4. Coalesce identical cargo

Define coalesce-cargo to take an array of cars and group consecutive cars carrying the same cargo into runs.

{ "coal" "coal" "ore" "ore" "ore" "timber" "coal" } coalesce-cargo .
! => { { "coal" "coal" } { "ore" "ore" "ore" } { "timber" } { "coal" } }
Edit via GitHub The link opens in a new window or tab
Factor Exercism

Ready to start Belgian Boxcars?

Sign up to Exercism to learn and master Factor with 47 concepts163 exercises, and real human mentoring, all for free.