From 6b64ea7d1a397033c770df2874dbc892ee8efec0 Mon Sep 17 00:00:00 2001 From: Steve Lamb Date: Thu, 27 Mar 2014 16:23:51 -0400 Subject: [PATCH] Add functions for flexibly zipping uneven lists fixes #84 on github. Add -zip-fill, -cycle and -pad. --- README.md | 37 ++++++++++++++++++++++++++++++++++++- dash.el | 19 +++++++++++++++++++ dev/examples.el | 17 +++++++++++++++++ readme-template.md | 2 +- 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 155284f..092aa55 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,9 @@ Operations dual to reductions, building lists from seed value rather than consum * [-interleave](#-interleave-rest-lists) `(&rest lists)` * [-zip-with](#-zip-with-fn-list1-list2) `(fn list1 list2)` * [-zip](#-zip-rest-lists) `(&rest lists)` +* [-zip-fill](#-zip-fill-fill-value-rest-lists) `(fill-value &rest lists)` +* [-cycle](#-cycle-list) `(list)` +* [-pad](#-pad-fill-value-rest-lists) `(fill-value &rest lists)` * [-annotate](#-annotate-fn-list) `(fn list)` * [-first](#-first-pred-list) `(pred list)` * [-last](#-last-pred-list) `(pred list)` @@ -1104,6 +1107,38 @@ of cons cells. Otherwise, return the groupings as a list of lists. (-zip '(1 2 3 4) '(4 5 6)) ;; => '((1 . 4) (2 . 5) (3 . 6)) ``` +#### -zip-fill `(fill-value &rest lists)` + +Zip `lists`, with `fill-value` padded onto the shorter lists. The +lengths of the returned groupings are equal to the length of the +longest input list. + +```cl +(-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9)) ;; => '((1 . 6) (2 . 7) (3 . 8) (4 . 9) (5 . 0)) +``` + +#### -cycle `(list)` + +Returns an infinite copy of `list` that will cycle through the +elements and repeat from the beginning. + +```cl +(-take 5 (-cycle '(1 2 3))) ;; => '(1 2 3 1 2) +(-take 7 (-cycle '(1 "and" 3))) ;; => '(1 "and" 3 1 "and" 3 1) +(-zip (-cycle '(1 2 3)) '(1 2)) ;; => '((1 . 1) (2 . 2)) +``` + +#### -pad `(fill-value &rest lists)` + +Appends `fill-value` to the end of each list in `lists` such that they +will all have the same length. + +```cl +(-pad 0 '()) ;; => '(nil) +(-pad 0 '(1)) ;; => '((1)) +(-pad 0 '(1 2 3) '(4 5)) ;; => '((1 2 3) (4 5 0)) +``` + #### -annotate `(fn list)` Returns a list of cons cells where each cell is `fn` applied to each @@ -1681,7 +1716,7 @@ Change `readme-template.md` or `examples-to-docs.el` instead. - [Emanuel Evans](https://github.com/shosti) contributed `-if-let`, `-when-let` and `-insert-at`. - [Johan Andersson](https://github.com/rejeep) contributed `-sum`, `-product` and `-same-items?` - [Christina Whyte](https://github.com/kurisuwhyte) contributed `-compose` - - [Steve Lamb](https://github.com/steventlamb) contributed `-annotate` and an n-ary version of `-zip` + - [Steve Lamb](https://github.com/steventlamb) contributed `-cycle`, `-pad`, `-annotate`, `-zip-fill` and an n-ary version of `-zip`. Thanks! diff --git a/dash.el b/dash.el index ef09873..2e2eccf 100644 --- a/dash.el +++ b/dash.el @@ -814,6 +814,25 @@ of cons cells. Otherwise, return the groupings as a list of lists. " (--map (cons (car it) (cadr it)) results) results))) +(defun -zip-fill (fill-value &rest lists) + "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The +lengths of the returned groupings are equal to the length of the +longest input list." + (apply '-zip (apply '-pad (cons fill-value lists)))) + +(defun -cycle (list) + "Returns an infinite copy of LIST that will cycle through the +elements and repeat from the beginning." + (let ((newlist (-map 'identity list))) + (nconc newlist newlist))) + +(defun -pad (fill-value &rest lists) + "Appends FILL-VALUE to the end of each list in LISTS such that they +will all have the same length." + (let* ((annotations (-annotate 'length lists)) + (n (-max (-map 'car annotations)))) + (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations))) + (defun -annotate (fn list) "Returns a list of cons cells where each cell is FN applied to each element of LIST paired with the unmodified element of LIST." diff --git a/dev/examples.el b/dev/examples.el index 836d915..9520f44 100644 --- a/dev/examples.el +++ b/dev/examples.el @@ -439,6 +439,23 @@ (-zip '(1 2 3) '(4 5 6) '(7 8 9)) => '((1 4 7) (2 5 8) (3 6 9)) (-zip '(1 2) '(3 4 5) '(6)) => '((1 3 6))) + (defexamples -zip-fill + (-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9)) => '((1 . 6) (2 . 7) (3 . 8) (4 . 9) (5 . 0))) + + (defexamples -cycle + (-take 5 (-cycle '(1 2 3))) => '(1 2 3 1 2) + (-take 7 (-cycle '(1 "and" 3))) => '(1 "and" 3 1 "and" 3 1) + (-zip (-cycle '(1 2 3)) '(1 2)) => '((1 . 1) (2 . 2)) + (-zip-with 'cons (-cycle '(1 2 3)) '(1 2)) => '((1 . 1) (2 . 2)) + (-map (-partial '-take 5) (-split-at 5 (-cycle '(1 2 3)))) => '((1 2 3 1 2) (3 1 2 3 1))) + + (defexamples -pad + (-pad 0 '()) => '(()) + (-pad 0 '(1)) => '((1)) + (-pad 0 '(1 2 3) '(4 5)) => '((1 2 3) (4 5 0)) + (-pad nil '(1 2 3) '(4 5) '(6 7 8 9 10)) => '((1 2 3 nil nil) (4 5 nil nil nil) (6 7 8 9 10)) + (-pad 0 '(1 2) '(3 4)) => '((1 2) (3 4))) + (defexamples -annotate (-annotate '1+ '(1 2 3)) => '((2 . 1) (3 . 2) (4 . 3)) (-annotate 'length '(("h" "e" "l" "l" "o") ("hello" "world"))) => '((5 . ("h" "e" "l" "l" "o")) (2 . ("hello" "world"))) diff --git a/readme-template.md b/readme-template.md index ae51a32..68b8b41 100644 --- a/readme-template.md +++ b/readme-template.md @@ -174,7 +174,7 @@ Change `readme-template.md` or `examples-to-docs.el` instead. - [Emanuel Evans](https://github.com/shosti) contributed `-if-let`, `-when-let` and `-insert-at`. - [Johan Andersson](https://github.com/rejeep) contributed `-sum`, `-product` and `-same-items?` - [Christina Whyte](https://github.com/kurisuwhyte) contributed `-compose` - - [Steve Lamb](https://github.com/steventlamb) contributed `-annotate` and an n-ary version of `-zip` + - [Steve Lamb](https://github.com/steventlamb) contributed `-cycle`, `-pad`, `-annotate`, `-zip-fill` and an n-ary version of `-zip`. Thanks!