有时你需要把一个序列看成一系列片段,而不是逐个元素地看。grouping、splitting和splitting.monotonic这几个词汇表提供了四种做法。
group:大小为 n 的不重叠分块group ( seq n -- groups )
USING: grouping ;
{ 1 2 3 4 5 6 7 } 3 group .
! => { { 1 2 3 } { 4 5 6 } { 7 } }
如果序列的长度不是 n 的倍数,最后一组会比 n 短。
clump:大小为 n 的重叠滑动窗口clump ( seq n -- clumps )
USING: grouping ;
{ 1 2 3 4 5 } 2 clump .
! => { { 1 2 } { 2 3 } { 3 4 } { 4 5 } }
如果序列比 n 短,结果就是空的。
split-when:在谓词成立的位置断开split-when ( seq quot: ( elt -- ? ) -- pieces )
USING: splitting ;
{ 1 2 0 3 4 0 5 } [ zero? ] split-when .
! => { { 1 2 } { 3 4 } { 5 } }
每个元素都会单独调用一次谓词;返回真值的元素就是断点,不会保留在结果里。
monotonic-split:相邻元素对检查失败时断开连续段monotonic-split ( seq quot: ( a b -- ? ) -- pieces )
USING: splitting.monotonic ;
{ 1 1 2 2 2 3 } [ = ] monotonic-split .
! => { { 1 1 } { 2 2 2 } { 3 } }
谓词作用于相邻的两个元素。只要它返回真值,当前连续段就继续延伸;一旦返回 f,就开启新的连续段。用 [ = ] 会得到由相等元素组成的连续段,用 [ <= ] 会得到非递减的连续段,诸如此类。
group/clump:你已经知道想要的大小。split-when:你已经知道断点元素长什么样。monotonic-split:你知道什么条件会让相邻的两个元素仍然属于同一段。安特卫普编组站又是一个忙碌的夜晚。你是当班的调度员:驶入的货车要重新编组成出发列车,车钩要逐一检查,线路要在道岔处拆分,相同的货物要归并到一起以便计费。
每节车厢都是一个字符串,标明它装载的货物:"coal"、"timber"、"crates" 等。
定义couple,接收一个车厢数组和一个长度n,返回若干列互不重叠的列车,每列n节车厢。如果车厢总数不能整除,最后一列列车可以短一些。
{ "coal" "coal" "coke" "ore" "ore" "timber" "timber" } 3 couple .
! => { { "coal" "coal" "coke" } { "ore" "ore" "timber" } { "timber" } }
定义peek-couplings,接收一个车厢数组,返回每一对相邻车厢,好让检查员逐处查看车钩。
{ "coal" "ore" "timber" "crates" } peek-couplings .
! => { { "coal" "ore" } { "ore" "timber" } { "timber" "crates" } }
定义split-at-junctions,接收一个车厢数组和一个junctions数组(标记断点的车厢),返回各节道岔车厢之间的区段。道岔车厢本身不保留。
{ "coal" "coal" "switch" "ore" "switch" "timber" }
{ "switch" } split-at-junctions .
! => { { "coal" "coal" } { "ore" } { "timber" } }
定义coalesce-cargo,接收一个车厢数组,把装载相同货物的连续车厢归并成一段。
{ "coal" "coal" "ore" "ore" "ore" "timber" "coal" } coalesce-cargo .
! => { { "coal" "coal" } { "ore" "ore" "ore" } { "timber" } { "coal" } }