List Slices
October 27, 2020
This is an extension of the Standard Prelude function split to multiple sub-lists:
(define (slice widths xs) (let loop ((ws widths) (xs xs) (zs (list))) (if (null? ws) (reverse zs) (let-values (((front back) (split (car ws) xs))) (loop (cdr ws) back (cons front zs))))))
And here it is in action:
> (slice '(1 2 3) '(1 2 2 3 3 3)) ((1) (2 2) (3 3 3)) > (slice '(1 2 3) '(1 2 2 3)) ((1) (2 2) (3)) > (slice '(1 2 3) '(1 2 2)) ((1) (2 2) ()) > (slice '(1 2 3) '(1 2 2 3 3 3 4 4 4 4)) ((1) (2 2) (3 3 3))
Here’s a way to print a telephone number in a canonical format:
> (let ((xs (map list->string (slice '(3 3 4) (filter char-numeric? (string->list "123.456.7890")))))) (string-append "(" (car xs) ")" (cadr xs) "-" (caddr xs))) "(123)456-7890"
You can run the program at https://ideone.com/f2xNRM. I’ll probably add this function to the next version of the Standard Prelude.
Here is an implementation in standard Scheme with no additional dependencies.
Output:
Here is my take on this using Julia 1.5: https://pastebin.com/MiMuvK3V
Pretty straight-forward, through the types need some attention since there is no null for Integers, so I had to use Reals in the output array. Cheers!
Here are two solutions in Python, the first with explicit calculation of slicing indices, and the second relying on
itertools.accumulate
.Output:
Here’s a couple of Haskell solutions, one using an explicit recursion, the other doing a combined map and fold with mapAccumL:
In common lisp by mapping a recursive function that returns a list of k elements from a list over the list of lengths.
(defun slice-list (seq n)
(labels ((rec (s k)
(if (= k 0)
nil
(cons (car s)
(rec (cdr s) (- k 1))))))
(let ((offset 0))
(map 'list
(lambda (k)
(let ((new-offset offset))
(incf offset k)
(rec (subseq seq new-offset) k)))
n))))
(slice-list '(1 2 2 3 3 3) '(1 2 3))
; ((1) (2 2) (3 3 3))
(slice-list '(1 2 2 3 3 3) '(1 2 5))
;((1) (2 2) (3 3 3 NIL NIL))
(slice-list '(1 2 2 3 3 3) '(1 2 1))
;((1) (2 2) (3))