From 8f405683155dbc317d1570b82273891d4641ae91 Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Fri, 24 Feb 2023 20:57:59 +0100 Subject: [PATCH] Test recent changes * dev/examples.el (-remove-at, -remove-at-indices, -zip-with) (-zip-lists, -zip, -zip-fill, -unzip): Extend tests. (-cycle): Avoid dyadic -zip. (-zip-pair, -zip-lists-fill, -unzip-lists, dash--length=): New tests. (-prodfn): Simplify test. * README.md: * dash.texi: Regenerate docs. --- README.md | 217 ++++++++++++++++-------- dash.texi | 271 +++++++++++++++++++++--------- dev/examples.el | 436 +++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 714 insertions(+), 210 deletions(-) diff --git a/README.md b/README.md index b9712bf1..e4ccf91d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@ See the end of the file for license conditions. ## Contents * [Change log](#change-log) - * [Upcoming breaking change!](#upcoming-breaking-change) * [Installation](#installation) * [Functions](#functions) * [Contribute](#contribute) @@ -25,18 +24,6 @@ See the end of the file for license conditions. See the [`NEWS.md`](NEWS.md) file. -### Upcoming breaking change! - -- For backward compatibility reasons, `-zip` when called with two - lists returns a list of cons cells, rather than a list of proper - lists. This is a clunky API, and may be changed in a future release - to always return a list of proper lists, as `-zip-lists` currently - does. - - **N.B.:** Do not rely on the current behavior of `-zip` for two - lists. Instead, use `-zip-pair` for a list of cons cells, and - `-zip-lists` for a list of proper lists. - ## Installation Dash is available on [GNU ELPA](https://elpa.gnu.org/), [GNU-devel @@ -287,9 +274,12 @@ Other list functions not fit to be classified elsewhere. * [`-interleave`](#-interleave-rest-lists) `(&rest lists)` * [`-iota`](#-iota-count-optional-start-step) `(count &optional start step)` * [`-zip-with`](#-zip-with-fn-list1-list2) `(fn list1 list2)` -* [`-zip`](#-zip-rest-lists) `(&rest lists)` +* [`-zip-pair`](#-zip-pair-list1-list2) `(list1 list2)` * [`-zip-lists`](#-zip-lists-rest-lists) `(&rest lists)` +* [`-zip-lists-fill`](#-zip-lists-fill-fill-value-rest-lists) `(fill-value &rest lists)` +* [`-zip`](#-zip-rest-lists) `(&rest lists)` * [`-zip-fill`](#-zip-fill-fill-value-rest-lists) `(fill-value &rest lists)` +* [`-unzip-lists`](#-unzip-lists-lists) `(lists)` * [`-unzip`](#-unzip-lists) `(lists)` * [`-pad`](#-pad-fill-value-rest-lists) `(fill-value &rest lists)` * [`-table`](#-table-fn-rest-lists) `(fn &rest lists)` @@ -927,28 +917,38 @@ See also: [`-map-when`](#-map-when-pred-rep-list) #### -remove-at `(n list)` -Return a list with element at `n`th position in `list` removed. +Return `list` with its element at index `n` removed. +That is, remove any element selected as (nth `n` `list`) from `list` +and return the result. -See also: [`-remove-at-indices`](#-remove-at-indices-indices-list), [`-remove`](#-remove-pred-list) +This is a non-destructive operation: parts of `list` (but not +necessarily all of it) are copied as needed to avoid +destructively modifying it. + +See also: [`-remove-at-indices`](#-remove-at-indices-indices-list), [`-remove`](#-remove-pred-list). ```el -(-remove-at 0 '("0" "1" "2" "3" "4" "5")) ;; => ("1" "2" "3" "4" "5") -(-remove-at 1 '("0" "1" "2" "3" "4" "5")) ;; => ("0" "2" "3" "4" "5") -(-remove-at 2 '("0" "1" "2" "3" "4" "5")) ;; => ("0" "1" "3" "4" "5") +(-remove-at 0 '(a b c)) ;; => (b c) +(-remove-at 1 '(a b c)) ;; => (a c) +(-remove-at 2 '(a b c)) ;; => (a b) ``` #### -remove-at-indices `(indices list)` -Return a list whose elements are elements from `list` without -elements selected as `(nth i list)` for all i -from `indices`. +Return `list` with its elements at `indices` removed. +That is, for each index `i` in `indices`, remove any element selected +as (nth `i` `list`) from `list`. + +This is a non-destructive operation: parts of `list` (but not +necessarily all of it) are copied as needed to avoid +destructively modifying it. -See also: [`-remove-at`](#-remove-at-n-list), [`-remove`](#-remove-pred-list) +See also: [`-remove-at`](#-remove-at-n-list), [`-remove`](#-remove-pred-list). ```el -(-remove-at-indices '(0) '("0" "1" "2" "3" "4" "5")) ;; => ("1" "2" "3" "4" "5") -(-remove-at-indices '(0 2 4) '("0" "1" "2" "3" "4" "5")) ;; => ("1" "3" "5") -(-remove-at-indices '(0 5) '("0" "1" "2" "3" "4" "5")) ;; => ("1" "2" "3" "4") +(-remove-at-indices '(0) '(a b c d e)) ;; => (b c d e) +(-remove-at-indices '(1 3) '(a b c d e)) ;; => (a c e) +(-remove-at-indices '(4 0 2) '(a b c d e)) ;; => (b d) ``` ## Reductions @@ -1326,7 +1326,7 @@ from the beginning. ```el (-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-lists (-cycle '(3)) '(1 2)) ;; => ((3 1) (3 2)) ``` ## Predicates @@ -1982,53 +1982,52 @@ the `apl` language. #### -zip-with `(fn list1 list2)` -Zip the two lists `list1` and `list2` using a function `fn`. This -function is applied pairwise taking as first argument element of -`list1` and as second argument element of `list2` at corresponding -position. +Zip `list1` and `list2` into a new list using the function `fn`. +That is, apply `fn` pairwise taking as first argument the next +element of `list1` and as second argument the next element of `list2` +at the corresponding position. The result is as long as the +shorter list. + +This function's anaphoric counterpart is `--zip-with`. -The anaphoric form `--zip-with` binds the elements from `list1` as symbol `it`, -and the elements from `list2` as symbol `other`. +For other zips, see also [`-zip-lists`](#-zip-lists-rest-lists) and [`-zip-fill`](#-zip-fill-fill-value-rest-lists). ```el -(-zip-with '+ '(1 2 3) '(4 5 6)) ;; => (5 7 9) -(-zip-with 'cons '(1 2 3) '(4 5 6)) ;; => ((1 . 4) (2 . 5) (3 . 6)) -(--zip-with (concat it " and " other) '("Batman" "Jekyll") '("Robin" "Hyde")) ;; => ("Batman and Robin" "Jekyll and Hyde") +(-zip-with #'+ '(1 2 3 4) '(5 6 7)) ;; => (6 8 10) +(-zip-with #'cons '(1 2 3) '(4 5 6 7)) ;; => ((1 . 4) (2 . 5) (3 . 6)) +(--zip-with (format "%s & %s" it other) '(Batman Jekyll) '(Robin Hyde)) ;; => ("Batman & Robin" "Jekyll & Hyde") ``` -#### -zip `(&rest lists)` - -Zip `lists` together. Group the head of each list, followed by the -second elements of each list, and so on. The lengths of the returned -groupings are equal to the length of the shortest input list. +#### -zip-pair `(list1 list2)` -If two lists are provided as arguments, return the groupings as a list -of cons cells. Otherwise, return the groupings as a list of lists. +Zip `list1` and `list2` together. -Use [`-zip-lists`](#-zip-lists-rest-lists) if you need the return value to always be a list -of lists. +Make a pair with the head of each list, followed by a pair with +the second element of each list, and so on. The number of pairs +returned is equal to the length of the shorter input list. -Alias: `-zip-pair` - -See also: [`-zip-lists`](#-zip-lists-rest-lists) +See also: [`-zip-lists`](#-zip-lists-rest-lists). ```el -(-zip '(1 2 3) '(4 5 6)) ;; => ((1 . 4) (2 . 5) (3 . 6)) -(-zip '(1 2 3) '(4 5 6 7)) ;; => ((1 . 4) (2 . 5) (3 . 6)) -(-zip '(1 2) '(3 4 5) '(6)) ;; => ((1 3 6)) +(-zip-pair '(1 2 3 4) '(5 6 7)) ;; => ((1 . 5) (2 . 6) (3 . 7)) +(-zip-pair '(1 2 3) '(4 5 6)) ;; => ((1 . 4) (2 . 5) (3 . 6)) +(-zip-pair '(1 2) '(3)) ;; => ((1 . 3)) ``` #### -zip-lists `(&rest lists)` -Zip `lists` together. Group the head of each list, followed by the -second elements of each list, and so on. The lengths of the returned -groupings are equal to the length of the shortest input list. +Zip `lists` together. + +Group the head of each list, followed by the second element of +each list, and so on. The number of returned groupings is equal +to the length of the shortest input list, and the length of each +grouping is equal to the number of input `lists`. -The return value is always list of lists, which is a difference -from `-zip-pair` which returns a cons-cell in case two input -lists are provided. +The return value is always a list of proper lists, in contrast to +[`-zip`](#-zip-rest-lists) which returns a list of dotted pairs when only two input +`lists` are provided. -See also: [`-zip`](#-zip-rest-lists) +See also: [`-zip-pair`](#-zip-pair-list1-list2). ```el (-zip-lists '(1 2 3) '(4 5 6)) ;; => ((1 4) (2 5) (3 6)) @@ -2036,36 +2035,106 @@ See also: [`-zip`](#-zip-rest-lists) (-zip-lists '(1 2) '(3 4 5) '(6)) ;; => ((1 3 6)) ``` +#### -zip-lists-fill `(fill-value &rest lists)` + +Zip `lists` together, padding shorter lists with `fill-value`. +This is like [`-zip-lists`](#-zip-lists-rest-lists) (which see), except it retains all +elements at positions beyond the end of the shortest list. The +number of returned groupings is equal to the length of the +longest input list, and the length of each grouping is equal to +the number of input `lists`. + +```el +(-zip-lists-fill 0 '(1 2) '(3 4 5) '(6)) ;; => ((1 3 6) (2 4 0) (0 5 0)) +(-zip-lists-fill 0 '(1 2) '(3 4) '(5 6)) ;; => ((1 3 5) (2 4 6)) +(-zip-lists-fill 0 '(1 2 3) nil) ;; => ((1 0) (2 0) (3 0)) +``` + +#### -zip `(&rest lists)` + +Zip `lists` together. + +Group the head of each list, followed by the second element of +each list, and so on. The number of returned groupings is equal +to the length of the shortest input list, and the number of items +in each grouping is equal to the number of input `lists`. + +If only two `lists` are provided as arguments, return the groupings +as a list of dotted pairs. Otherwise, return the groupings as a +list of proper lists. + +Since the return value changes form depending on the number of +arguments, it is generally recommended to use [`-zip-lists`](#-zip-lists-rest-lists) +instead, or [`-zip-pair`](#-zip-pair-list1-list2) if a list of dotted pairs is desired. + +See also: [`-unzip`](#-unzip-lists). + +```el +(-zip '(1 2 3 4) '(5 6 7) '(8 9)) ;; => ((1 5 8) (2 6 9)) +(-zip '(1 2 3) '(4 5 6) '(7 8 9)) ;; => ((1 4 7) (2 5 8) (3 6 9)) +(-zip '(1 2 3)) ;; => ((1) (2) (3)) +``` + #### -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. +Zip `lists` together, padding shorter lists with `fill-value`. +This is like [`-zip`](#-zip-rest-lists) (which see), except it retains all elements +at positions beyond the end of the shortest list. The number of +returned groupings is equal to the length of the longest input +list, and the length of each grouping is equal to the number of +input `lists`. + +Since the return value changes form depending on the number of +arguments, it is generally recommended to use [`-zip-lists-fill`](#-zip-lists-fill-fill-value-rest-lists) +instead, unless a list of dotted pairs is explicitly desired. + +```el +(-zip-fill 0 '(1 2 3) '(4 5)) ;; => ((1 . 4) (2 . 5) (3 . 0)) +(-zip-fill 0 () '(1 2 3)) ;; => ((0 . 1) (0 . 2) (0 . 3)) +(-zip-fill 0 '(1 2) '(3 4) '(5 6)) ;; => ((1 3 5) (2 4 6)) +``` + +#### -unzip-lists `(lists)` + +Unzip `lists`. + +This works just like [`-zip-lists`](#-zip-lists-rest-lists) (which see), but takes a list +of lists instead of a variable number of arguments, such that + + (-unzip-lists (-zip-lists `args`...)) + +is identity (given that the lists comprising `args` are of the same +length). ```el -(-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9)) ;; => ((1 . 6) (2 . 7) (3 . 8) (4 . 9) (5 . 0)) +(-unzip-lists (-zip-lists '(1 2) '(3 4) '(5 6))) ;; => ((1 2) (3 4) (5 6)) +(-unzip-lists '((1 2 3) (4 5) (6 7) (8 9))) ;; => ((1 4 6 8) (2 5 7 9)) +(-unzip-lists '((1 2 3) (4 5 6))) ;; => ((1 4) (2 5) (3 6)) ``` #### -unzip `(lists)` Unzip `lists`. -This works just like [`-zip`](#-zip-rest-lists) but takes a list of lists instead of -a variable number of arguments, such that +This works just like [`-zip`](#-zip-rest-lists) (which see), but takes a list of +lists instead of a variable number of arguments, such that (-unzip (-zip `l1` `l2` `l3` ...)) -is identity (given that the lists are the same length). +is identity (given that the lists are of the same length, and +that [`-zip`](#-zip-rest-lists) is not called with two arguments, because of the +caveat described in its docstring). -Note in particular that calling this on a list of two lists will -return a list of cons-cells such that the above identity works. +Note in particular that calling [`-unzip`](#-unzip-lists) on a list of two lists +will return a list of dotted pairs. -See also: [`-zip`](#-zip-rest-lists) +Since the return value changes form depending on the number of +`lists`, it is generally recommended to use [`-unzip-lists`](#-unzip-lists-lists) instead. ```el -(-unzip (-zip '(1 2 3) '(a b c) '("e" "f" "g"))) ;; => ((1 2 3) (a b c) ("e" "f" "g")) -(-unzip '((1 2) (3 4) (5 6) (7 8) (9 10))) ;; => ((1 3 5 7 9) (2 4 6 8 10)) -(-unzip '((1 2) (3 4))) ;; => ((1 . 3) (2 . 4)) +(-unzip (-zip '(1 2) '(3 4) '(5 6))) ;; => ((1 . 2) (3 . 4) (5 . 6)) +(-unzip '((1 2 3) (4 5 6))) ;; => ((1 . 4) (2 . 5) (3 . 6)) +(-unzip '((1 2 3) (4 5) (6 7) (8 9))) ;; => ((1 4 6 8) (2 5 7 9)) ``` #### -pad `(fill-value &rest lists)` @@ -3204,9 +3273,9 @@ This function satisfies the following laws: = (-compose fn (-partial #'nth n)) ```el -(funcall (-prodfn '1+ '1- 'number-to-string) '(1 2 3)) ;; => (2 1 "3") -(-map (-prodfn '1+ '1-) '((1 2) (3 4) (5 6) (7 8))) ;; => ((2 1) (4 3) (6 5) (8 7)) -(apply '+ (funcall (-prodfn 'length 'string-to-number) '((1 2 3) "15"))) ;; => 18 +(funcall (-prodfn #'1+ #'1- #'number-to-string) '(1 2 3)) ;; => (2 1 "3") +(-map (-prodfn #'1- #'1+) '((1 2) (3 4) (5 6))) ;; => ((0 3) (2 5) (4 7)) +(apply #'+ (funcall (-prodfn #'length #'string-to-number) '((t) "5"))) ;; => 6 ``` ## Contribute diff --git a/dash.texi b/dash.texi index 9226c304..529294c6 100644 --- a/dash.texi +++ b/dash.texi @@ -1120,46 +1120,56 @@ See also: @code{-map-when} (@pxref{-map-when}) @anchor{-remove-at} @defun -remove-at (n list) -Return a list with element at Nth position in @var{list} removed. +Return @var{list} with its element at index @var{n} removed. +That is, remove any element selected as (nth @var{n} @var{list}) from @var{list} +and return the result. -See also: @code{-remove-at-indices} (@pxref{-remove-at-indices}), @code{-remove} (@pxref{-remove}) +This is a non-destructive operation: parts of @var{list} (but not +necessarily all of it) are copied as needed to avoid +destructively modifying it. + +See also: @code{-remove-at-indices} (@pxref{-remove-at-indices}), @code{-remove} (@pxref{-remove}). @example @group -(-remove-at 0 '("0" "1" "2" "3" "4" "5")) - @result{} ("1" "2" "3" "4" "5") +(-remove-at 0 '(a b c)) + @result{} (b c) @end group @group -(-remove-at 1 '("0" "1" "2" "3" "4" "5")) - @result{} ("0" "2" "3" "4" "5") +(-remove-at 1 '(a b c)) + @result{} (a c) @end group @group -(-remove-at 2 '("0" "1" "2" "3" "4" "5")) - @result{} ("0" "1" "3" "4" "5") +(-remove-at 2 '(a b c)) + @result{} (a b) @end group @end example @end defun @anchor{-remove-at-indices} @defun -remove-at-indices (indices list) -Return a list whose elements are elements from @var{list} without -elements selected as `(nth i list)` for all i -from @var{indices}. +Return @var{list} with its elements at @var{indices} removed. +That is, for each index @var{i} in @var{indices}, remove any element selected +as (nth @var{i} @var{list}) from @var{list}. + +This is a non-destructive operation: parts of @var{list} (but not +necessarily all of it) are copied as needed to avoid +destructively modifying it. -See also: @code{-remove-at} (@pxref{-remove-at}), @code{-remove} (@pxref{-remove}) +See also: @code{-remove-at} (@pxref{-remove-at}), @code{-remove} (@pxref{-remove}). @example @group -(-remove-at-indices '(0) '("0" "1" "2" "3" "4" "5")) - @result{} ("1" "2" "3" "4" "5") +(-remove-at-indices '(0) '(a b c d e)) + @result{} (b c d e) @end group @group -(-remove-at-indices '(0 2 4) '("0" "1" "2" "3" "4" "5")) - @result{} ("1" "3" "5") +(-remove-at-indices '(1 3) '(a b c d e)) + @result{} (a c e) @end group @group -(-remove-at-indices '(0 5) '("0" "1" "2" "3" "4" "5")) - @result{} ("1" "2" "3" "4") +(-remove-at-indices '(4 0 2) '(a b c d e)) + @result{} (b d) @end group @end example @end defun @@ -1795,8 +1805,8 @@ from the beginning. @result{} (1 "and" 3 1 "and" 3 1) @end group @group -(-zip (-cycle '(1 2 3)) '(1 2)) - @result{} ((1 . 1) (2 . 2)) +(-zip-lists (-cycle '(3)) '(1 2)) + @result{} ((3 1) (3 2)) @end group @end example @end defun @@ -2923,73 +2933,72 @@ the @var{apl} language. @anchor{-zip-with} @defun -zip-with (fn list1 list2) -Zip the two lists @var{list1} and @var{list2} using a function @var{fn}. This -function is applied pairwise taking as first argument element of -@var{list1} and as second argument element of @var{list2} at corresponding -position. +Zip @var{list1} and @var{list2} into a new list using the function @var{fn}. +That is, apply @var{fn} pairwise taking as first argument the next +element of @var{list1} and as second argument the next element of @var{list2} +at the corresponding position. The result is as long as the +shorter list. -The anaphoric form @code{--zip-with} binds the elements from @var{list1} as symbol @code{it}, -and the elements from @var{list2} as symbol @code{other}. +This function's anaphoric counterpart is @code{--zip-with}. + +For other zips, see also @code{-zip-lists} (@pxref{-zip-lists}) and @code{-zip-fill} (@pxref{-zip-fill}). @example @group -(-zip-with '+ '(1 2 3) '(4 5 6)) - @result{} (5 7 9) +(-zip-with #'+ '(1 2 3 4) '(5 6 7)) + @result{} (6 8 10) @end group @group -(-zip-with 'cons '(1 2 3) '(4 5 6)) +(-zip-with #'cons '(1 2 3) '(4 5 6 7)) @result{} ((1 . 4) (2 . 5) (3 . 6)) @end group @group -(--zip-with (concat it " and " other) '("Batman" "Jekyll") '("Robin" "Hyde")) - @result{} ("Batman and Robin" "Jekyll and Hyde") +(--zip-with (format "%s & %s" it other) '(Batman Jekyll) '(Robin Hyde)) + @result{} ("Batman & Robin" "Jekyll & Hyde") @end group @end example @end defun -@anchor{-zip} -@defun -zip (&rest lists) -Zip @var{lists} together. Group the head of each list, followed by the -second elements of each list, and so on. The lengths of the returned -groupings are equal to the length of the shortest input list. - -If two lists are provided as arguments, return the groupings as a list -of cons cells. Otherwise, return the groupings as a list of lists. +@anchor{-zip-pair} +@defun -zip-pair (list1 list2) +Zip @var{list1} and @var{list2} together. -Use @code{-zip-lists} (@pxref{-zip-lists}) if you need the return value to always be a list -of lists. +Make a pair with the head of each list, followed by a pair with +the second element of each list, and so on. The number of pairs +returned is equal to the length of the shorter input list. -Alias: @code{-zip-pair} - -See also: @code{-zip-lists} (@pxref{-zip-lists}) +See also: @code{-zip-lists} (@pxref{-zip-lists}). @example @group -(-zip '(1 2 3) '(4 5 6)) - @result{} ((1 . 4) (2 . 5) (3 . 6)) +(-zip-pair '(1 2 3 4) '(5 6 7)) + @result{} ((1 . 5) (2 . 6) (3 . 7)) @end group @group -(-zip '(1 2 3) '(4 5 6 7)) +(-zip-pair '(1 2 3) '(4 5 6)) @result{} ((1 . 4) (2 . 5) (3 . 6)) @end group @group -(-zip '(1 2) '(3 4 5) '(6)) - @result{} ((1 3 6)) +(-zip-pair '(1 2) '(3)) + @result{} ((1 . 3)) @end group @end example @end defun @anchor{-zip-lists} @defun -zip-lists (&rest lists) -Zip @var{lists} together. Group the head of each list, followed by the -second elements of each list, and so on. The lengths of the returned -groupings are equal to the length of the shortest input list. +Zip @var{lists} together. + +Group the head of each list, followed by the second element of +each list, and so on. The number of returned groupings is equal +to the length of the shortest input list, and the length of each +grouping is equal to the number of input @var{lists}. -The return value is always list of lists, which is a difference -from @code{-zip-pair} which returns a cons-cell in case two input -lists are provided. +The return value is always a list of proper lists, in contrast to +@code{-zip} (@pxref{-zip}) which returns a list of dotted pairs when only two input +@var{lists} are provided. -See also: @code{-zip} (@pxref{-zip}) +See also: @code{-zip-pair} (@pxref{-zip-pair}). @example @group @@ -3007,16 +3016,119 @@ See also: @code{-zip} (@pxref{-zip}) @end example @end defun +@anchor{-zip-lists-fill} +@defun -zip-lists-fill (fill-value &rest lists) +Zip @var{lists} together, padding shorter lists with @var{fill-value}. +This is like @code{-zip-lists} (@pxref{-zip-lists}) (which see), except it retains all +elements at positions beyond the end of the shortest list. The +number of returned groupings is equal to the length of the +longest input list, and the length of each grouping is equal to +the number of input @var{lists}. + +@example +@group +(-zip-lists-fill 0 '(1 2) '(3 4 5) '(6)) + @result{} ((1 3 6) (2 4 0) (0 5 0)) +@end group +@group +(-zip-lists-fill 0 '(1 2) '(3 4) '(5 6)) + @result{} ((1 3 5) (2 4 6)) +@end group +@group +(-zip-lists-fill 0 '(1 2 3) nil) + @result{} ((1 0) (2 0) (3 0)) +@end group +@end example +@end defun + +@anchor{-zip} +@defun -zip (&rest lists) +Zip @var{lists} together. + +Group the head of each list, followed by the second element of +each list, and so on. The number of returned groupings is equal +to the length of the shortest input list, and the number of items +in each grouping is equal to the number of input @var{lists}. + +If only two @var{lists} are provided as arguments, return the groupings +as a list of dotted pairs. Otherwise, return the groupings as a +list of proper lists. + +Since the return value changes form depending on the number of +arguments, it is generally recommended to use @code{-zip-lists} (@pxref{-zip-lists}) +instead, or @code{-zip-pair} (@pxref{-zip-pair}) if a list of dotted pairs is desired. + +See also: @code{-unzip} (@pxref{-unzip}). + +@example +@group +(-zip '(1 2 3 4) '(5 6 7) '(8 9)) + @result{} ((1 5 8) (2 6 9)) +@end group +@group +(-zip '(1 2 3) '(4 5 6) '(7 8 9)) + @result{} ((1 4 7) (2 5 8) (3 6 9)) +@end group +@group +(-zip '(1 2 3)) + @result{} ((1) (2) (3)) +@end group +@end example +@end defun + @anchor{-zip-fill} @defun -zip-fill (fill-value &rest lists) -Zip @var{lists}, with @var{fill-value} padded onto the shorter lists. The -lengths of the returned groupings are equal to the length of the -longest input list. +Zip @var{lists} together, padding shorter lists with @var{fill-value}. +This is like @code{-zip} (@pxref{-zip}) (which see), except it retains all elements +at positions beyond the end of the shortest list. The number of +returned groupings is equal to the length of the longest input +list, and the length of each grouping is equal to the number of +input @var{lists}. + +Since the return value changes form depending on the number of +arguments, it is generally recommended to use @code{-zip-lists-fill} (@pxref{-zip-lists-fill}) +instead, unless a list of dotted pairs is explicitly desired. @example @group -(-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9)) - @result{} ((1 . 6) (2 . 7) (3 . 8) (4 . 9) (5 . 0)) +(-zip-fill 0 '(1 2 3) '(4 5)) + @result{} ((1 . 4) (2 . 5) (3 . 0)) +@end group +@group +(-zip-fill 0 () '(1 2 3)) + @result{} ((0 . 1) (0 . 2) (0 . 3)) +@end group +@group +(-zip-fill 0 '(1 2) '(3 4) '(5 6)) + @result{} ((1 3 5) (2 4 6)) +@end group +@end example +@end defun + +@anchor{-unzip-lists} +@defun -unzip-lists (lists) +Unzip @var{lists}. + +This works just like @code{-zip-lists} (@pxref{-zip-lists}) (which see), but takes a list +of lists instead of a variable number of arguments, such that + + (-unzip-lists (-zip-lists @var{args}@dots{})) + +is identity (given that the lists comprising @var{args} are of the same +length). + +@example +@group +(-unzip-lists (-zip-lists '(1 2) '(3 4) '(5 6))) + @result{} ((1 2) (3 4) (5 6)) +@end group +@group +(-unzip-lists '((1 2 3) (4 5) (6 7) (8 9))) + @result{} ((1 4 6 8) (2 5 7 9)) +@end group +@group +(-unzip-lists '((1 2 3) (4 5 6))) + @result{} ((1 4) (2 5) (3 6)) @end group @end example @end defun @@ -3025,30 +3137,33 @@ longest input list. @defun -unzip (lists) Unzip @var{lists}. -This works just like @code{-zip} (@pxref{-zip}) but takes a list of lists instead of -a variable number of arguments, such that +This works just like @code{-zip} (@pxref{-zip}) (which see), but takes a list of +lists instead of a variable number of arguments, such that (-unzip (-zip @var{l1} @var{l2} @var{l3} @dots{})) -is identity (given that the lists are the same length). +is identity (given that the lists are of the same length, and +that @code{-zip} (@pxref{-zip}) is not called with two arguments, because of the +caveat described in its docstring). -Note in particular that calling this on a list of two lists will -return a list of cons-cells such that the above identity works. +Note in particular that calling @code{-unzip} (@pxref{-unzip}) on a list of two lists +will return a list of dotted pairs. -See also: @code{-zip} (@pxref{-zip}) +Since the return value changes form depending on the number of +@var{lists}, it is generally recommended to use @code{-unzip-lists} (@pxref{-unzip-lists}) instead. @example @group -(-unzip (-zip '(1 2 3) '(a b c) '("e" "f" "g"))) - @result{} ((1 2 3) (a b c) ("e" "f" "g")) +(-unzip (-zip '(1 2) '(3 4) '(5 6))) + @result{} ((1 . 2) (3 . 4) (5 . 6)) @end group @group -(-unzip '((1 2) (3 4) (5 6) (7 8) (9 10))) - @result{} ((1 3 5 7 9) (2 4 6 8 10)) +(-unzip '((1 2 3) (4 5 6))) + @result{} ((1 . 4) (2 . 5) (3 . 6)) @end group @group -(-unzip '((1 2) (3 4))) - @result{} ((1 . 3) (2 . 4)) +(-unzip '((1 2 3) (4 5) (6 7) (8 9))) + @result{} ((1 4 6 8) (2 5 7 9)) @end group @end example @end defun @@ -4792,16 +4907,16 @@ This function satisfies the following laws: @example @group -(funcall (-prodfn '1+ '1- 'number-to-string) '(1 2 3)) +(funcall (-prodfn #'1+ #'1- #'number-to-string) '(1 2 3)) @result{} (2 1 "3") @end group @group -(-map (-prodfn '1+ '1-) '((1 2) (3 4) (5 6) (7 8))) - @result{} ((2 1) (4 3) (6 5) (8 7)) +(-map (-prodfn #'1- #'1+) '((1 2) (3 4) (5 6))) + @result{} ((0 3) (2 5) (4 7)) @end group @group -(apply '+ (funcall (-prodfn 'length 'string-to-number) '((1 2 3) "15"))) - @result{} 18 +(apply #'+ (funcall (-prodfn #'length #'string-to-number) '((t) "5"))) + @result{} 6 @end group @end example @end defun diff --git a/dev/examples.el b/dev/examples.el index 33cef8bb..85bf8747 100644 --- a/dev/examples.el +++ b/dev/examples.el @@ -466,34 +466,145 @@ new list." (--update-at 2 (concat it "zab") '("foo" "bar" "baz" "quux")) => '("foo" "bar" "bazzab" "quux")) (defexamples -remove-at - (-remove-at 0 '("0" "1" "2" "3" "4" "5")) => '("1" "2" "3" "4" "5") - (-remove-at 1 '("0" "1" "2" "3" "4" "5")) => '("0" "2" "3" "4" "5") - (-remove-at 2 '("0" "1" "2" "3" "4" "5")) => '("0" "1" "3" "4" "5") - (-remove-at 3 '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "4" "5") - (-remove-at 4 '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "3" "5") - (-remove-at 5 '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "3" "4") - (-remove-at 5 '((a b) (c d) (e f g) h i ((j) k) l (m))) => '((a b) (c d) (e f g) h i l (m)) - (-remove-at 0 '(((a b) (c d) (e f g) h i ((j) k) l (m)))) => nil) + (-remove-at 0 '(a b c)) => '(b c) + (-remove-at 1 '(a b c)) => '(a c) + (-remove-at 2 '(a b c)) => '(a b) + (-remove-at -1 ()) => () + (-remove-at 0 ()) => () + (-remove-at 1 ()) => () + (-remove-at -1 '(a)) => '(a) + (-remove-at 0 '(a)) => () + (-remove-at 1 '(a)) => '(a) + (-remove-at -1 '(a b)) => '(a b) + (-remove-at 0 '(a b)) => '(b) + (-remove-at 1 '(a b)) => '(a) + (-remove-at 2 '(a b)) => '(a b) + (-remove-at 0 '((a))) => () + (-remove-at 2 '((a) b (c . d) e)) => '((a) b e) + ;; Test for destructive modification. + (let ((l (list 0))) (ignore (-remove-at -1 l)) l) => '(0) + (let ((l (list 0))) (ignore (-remove-at 0 l)) l) => '(0) + (let ((l (list 0))) (ignore (-remove-at 1 l)) l) => '(0) + (let ((l (list 0 1))) (ignore (-remove-at -1 l)) l) => '(0 1) + (let ((l (list 0 1))) (ignore (-remove-at 0 l)) l) => '(0 1) + (let ((l (list 0 1))) (ignore (-remove-at 1 l)) l) => '(0 1) + (let ((l (list 0 1))) (ignore (-remove-at 2 l)) l) => '(0 1)) (defexamples -remove-at-indices - (-remove-at-indices '(0) '("0" "1" "2" "3" "4" "5")) => '("1" "2" "3" "4" "5") - (-remove-at-indices '(0 2 4) '("0" "1" "2" "3" "4" "5")) => '("1" "3" "5") - (-remove-at-indices '(0 5) '("0" "1" "2" "3" "4" "5")) => '("1" "2" "3" "4") - (-remove-at-indices '(1 2 3) '("0" "1" "2" "3" "4" "5")) => '("0" "4" "5") - (-remove-at-indices '(0 1 2 3 4 5) '("0" "1" "2" "3" "4" "5")) => nil - (-remove-at-indices '(2 0 4) '("0" "1" "2" "3" "4" "5")) => '("1" "3" "5") - (-remove-at-indices '(5 0) '("0" "1" "2" "3" "4" "5")) => '("1" "2" "3" "4") - (-remove-at-indices '(1 3 2) '("0" "1" "2" "3" "4" "5")) => '("0" "4" "5") - (-remove-at-indices '(0 3 4 2 5 1) '("0" "1" "2" "3" "4" "5")) => nil - (-remove-at-indices '(1) '("0" "1" "2" "3" "4" "5")) => '("0" "2" "3" "4" "5") - (-remove-at-indices '(2) '("0" "1" "2" "3" "4" "5")) => '("0" "1" "3" "4" "5") - (-remove-at-indices '(3) '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "4" "5") - (-remove-at-indices '(4) '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "3" "5") - (-remove-at-indices '(5) '("0" "1" "2" "3" "4" "5")) => '("0" "1" "2" "3" "4") - (-remove-at-indices '(1 2 4) '((a b) (c d) (e f g) h i ((j) k) l (m))) => '((a b) h ((j) k) l (m)) - (-remove-at-indices '(5) '((a b) (c d) (e f g) h i ((j) k) l (m))) => '((a b) (c d) (e f g) h i l (m)) - (-remove-at-indices '(0) '(((a b) (c d) (e f g) h i ((j) k) l (m)))) => nil - (-remove-at-indices '(2 3) '((0) (1) (2) (3) (4) (5) (6))) => '((0) (1) (4) (5) (6)))) + (-remove-at-indices '(0) '(a b c d e)) => '(b c d e) + (-remove-at-indices '(1 3) '(a b c d e)) => '(a c e) + (-remove-at-indices '(4 0 2) '(a b c d e)) => '(b d) + (-remove-at-indices () ()) => () + (-remove-at-indices '(-1) ()) => () + (-remove-at-indices '(0) ()) => () + (-remove-at-indices '(-1 0) ()) => () + (-remove-at-indices '(0 -1) ()) => () + (-remove-at-indices '(-1 -1) ()) => () + (-remove-at-indices '(0 0) ()) => () + (-remove-at-indices () '(a)) => '(a) + (-remove-at-indices '(-1) '(a)) => '(a) + (-remove-at-indices '(0) '(a)) => () + (-remove-at-indices '(1) '(a)) => '(a) + (-remove-at-indices '(-1 -1) '(a)) => '(a) + (-remove-at-indices '(-1 0) '(a)) => () + (-remove-at-indices '(0 -1) '(a)) => () + (-remove-at-indices '(-1 1) '(a)) => '(a) + (-remove-at-indices '(1 -1) '(a)) => '(a) + (-remove-at-indices '(0 0) '(a)) => () + (-remove-at-indices '(0 1) '(a)) => () + (-remove-at-indices '(1 0) '(a)) => () + (-remove-at-indices '(1 1) '(a)) => '(a) + (-remove-at-indices () '(a b)) => '(a b) + (-remove-at-indices '(-1) '(a b)) => '(a b) + (-remove-at-indices '(0) '(a b)) => '(b) + (-remove-at-indices '(1) '(a b)) => '(a) + (-remove-at-indices '(2) '(a b)) => '(a b) + (-remove-at-indices '(-2 -1) '(a b)) => '(a b) + (-remove-at-indices '(-1 -1) '(a b)) => '(a b) + (-remove-at-indices '(-1 0) '(a b)) => '(b) + (-remove-at-indices '(0 -1) '(a b)) => '(b) + (-remove-at-indices '(-1 1) '(a b)) => '(a) + (-remove-at-indices '(1 -1) '(a b)) => '(a) + (-remove-at-indices '(-1 2) '(a b)) => '(a b) + (-remove-at-indices '(2 -1) '(a b)) => '(a b) + (-remove-at-indices '(0 0) '(a b)) => '(b) + (-remove-at-indices '(0 1) '(a b)) => () + (-remove-at-indices '(1 0) '(a b)) => () + (-remove-at-indices '(0 2) '(a b)) => '(b) + (-remove-at-indices '(2 0) '(a b)) => '(b) + (-remove-at-indices '(1 1) '(a b)) => '(a) + (-remove-at-indices '(1 2) '(a b)) => '(a) + (-remove-at-indices '(2 1) '(a b)) => '(a) + (-remove-at-indices '(2 2) '(a b)) => '(a b) + (-remove-at-indices '(-1 0 0) '(a b)) => '(b) + (-remove-at-indices '(-1 0 1) '(a b)) => () + (-remove-at-indices '(-1 1 1) '(a b)) => '(a) + (-remove-at-indices '(1 -1 0) '(a b)) => () + (-remove-at-indices '(-1 -2 -3) '(a b)) => '(a b) + (-remove-at-indices '(4 3 2) '(a b)) => '(a b) + (-remove-at-indices '(0 0 0) '(a b)) => '(b) + (-remove-at-indices '(1 1 1) '(a b)) => '(a) + (-remove-at-indices () '(a b c)) => '(a b c) + (-remove-at-indices '(-1) '(a b c)) => '(a b c) + (-remove-at-indices '(3) '(a b c)) => '(a b c) + (-remove-at-indices '(-1 -1) '(a b c)) => '(a b c) + (-remove-at-indices '(-1 0) '(a b c)) => '(b c) + (-remove-at-indices '(0 -1) '(a b c)) => '(b c) + (-remove-at-indices '(-1 1) '(a b c)) => '(a c) + (-remove-at-indices '(1 -1) '(a b c)) => '(a c) + (-remove-at-indices '(-1 2) '(a b c)) => '(a b) + (-remove-at-indices '(2 -1) '(a b c)) => '(a b) + (-remove-at-indices '(-1 3) '(a b c)) => '(a b c) + (-remove-at-indices '(3 -1) '(a b c)) => '(a b c) + (-remove-at-indices '(-1 -2) '(a b c)) => '(a b c) + (-remove-at-indices '(3 3) '(a b c)) => '(a b c) + (-remove-at-indices '(4 3) '(a b c)) => '(a b c) + (-remove-at-indices '(2 -1 0) '(a b c)) => '(b) + (-remove-at-indices '(3 -1 2 1) '(a b c)) => '(a) + (-remove-at-indices '(3 0 -1 1) '(a b c)) => '(c) + (-remove-at-indices '(2 2 0 0) '(a b c)) => '(b) + (-remove-at-indices '(0 0 2) '(a b c)) => '(b) + (-remove-at-indices '(0) '(0 1 2 3 4 5)) => '(1 2 3 4 5) + (-remove-at-indices '(0 2 4) '(0 1 2 3 4 5)) => '(1 3 5) + (-remove-at-indices '(0 5) '(0 1 2 3 4 5)) => '(1 2 3 4) + (-remove-at-indices '(1 2 3) '(0 1 2 3 4 5)) => '(0 4 5) + (-remove-at-indices '(0 1 2 3 4 5) '(0 1 2 3 4 5)) => () + (-remove-at-indices '(2 0 4) '(0 1 2 3 4 5)) => '(1 3 5) + (-remove-at-indices '(5 0) '(0 1 2 3 4 5)) => '(1 2 3 4) + (-remove-at-indices '(1 3 2) '(0 1 2 3 4 5)) => '(0 4 5) + (-remove-at-indices '(0 3 4 2 5 1) '(0 1 2 3 4 5)) => () + (-remove-at-indices '(1) '(0 1 2 3 4 5)) => '(0 2 3 4 5) + (-remove-at-indices '(2) '(0 1 2 3 4 5)) => '(0 1 3 4 5) + (-remove-at-indices '(3) '(0 1 2 3 4 5)) => '(0 1 2 4 5) + (-remove-at-indices '(4) '(0 1 2 3 4 5)) => '(0 1 2 3 5) + (-remove-at-indices '(5) '(0 1 2 3 4 5)) => '(0 1 2 3 4) + (-remove-at-indices '(1 2 4) '((a b) (c d) (e f g) h i ((j) k) l (m))) + => '((a b) h ((j) k) l (m)) + (-remove-at-indices '(5) '((a b) (c d) (e f g) h i ((j) k) l (m))) + => '((a b) (c d) (e f g) h i l (m)) + (-remove-at-indices '(0) '(((a b) (c d) (e f g) h i ((j) k) l (m)))) => () + (-remove-at-indices '(2 3) '((0) (1) (2) (3) (4) (5) (6))) + => '((0) (1) (4) (5) (6)) + ;; Test for destructive modification. + (let ((l (list 0))) (ignore (-remove-at-indices '(0) l)) l) => '(0) + (let ((l (list 0 1))) (ignore (-remove-at-indices '(0) l)) l) => '(0 1) + (let ((l (list 0 1))) (ignore (-remove-at-indices '(1) l)) l) => '(0 1) + (let ((l (list 0 1))) (ignore (-remove-at-indices '(0 1) l)) l) => '(0 1) + (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(0) l)) l) => '(0 1 2) + (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(1) l)) l) => '(0 1 2) + (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(2) l)) l) => '(0 1 2) + (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(0 0) l)) l) + => '(0 1 2) + (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(0 1) l)) l) + => '(0 1 2) + (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(0 2) l)) l) + => '(0 1 2) + (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(1 1) l)) l) + => '(0 1 2) + (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(1 2) l)) l) + => '(0 1 2) + (let ((l (list 0 1 2))) (ignore (-remove-at-indices '(2 2) l)) l) + => '(0 1 2))) (def-example-group "Reductions" "Functions reducing lists to a single value (which may also be a list)." @@ -736,9 +847,10 @@ value rather than consuming a list to produce a single value." (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)) + (-zip-lists (-cycle '(3)) '(1 2)) => '((3 1) (3 2)) + (-zip-with #'cons (-cycle '(3)) '(1 2)) => '((3 . 1) (3 . 2)) + (--map (-take 5 it) (-split-at 5 (-cycle '(1 2 3)))) + => '((1 2 3 1 2) (3 1 2 3 1)) (let ((l (list 1))) (eq l (-cycle l))) => nil)) (def-example-group "Predicates" @@ -1468,17 +1580,60 @@ related predicates." (-iota 1 nil -1) => '(0)) (defexamples -zip-with - (-zip-with '+ '(1 2 3) '(4 5 6)) => '(5 7 9) - (-zip-with 'cons '(1 2 3) '(4 5 6)) => '((1 . 4) (2 . 5) (3 . 6)) - (--zip-with (concat it " and " other) '("Batman" "Jekyll") '("Robin" "Hyde")) => '("Batman and Robin" "Jekyll and Hyde")) - - (defexamples -zip - (-zip '(1 2 3) '(4 5 6)) => '((1 . 4) (2 . 5) (3 . 6)) - (-zip '(1 2 3) '(4 5 6 7)) => '((1 . 4) (2 . 5) (3 . 6)) - (-zip '(1 2) '(3 4 5) '(6)) => '((1 3 6)) - (-zip '(1 2 3 4) '(4 5 6)) => '((1 . 4) (2 . 5) (3 . 6)) - (-zip '(1 2 3) '(4 5 6) '(7 8 9)) => '((1 4 7) (2 5 8) (3 6 9)) - (-zip) => nil) + (-zip-with #'+ '(1 2 3 4) '(5 6 7)) => '(6 8 10) + (-zip-with #'cons '(1 2 3) '(4 5 6 7)) => '((1 . 4) (2 . 5) (3 . 6)) + (--zip-with (format "%s & %s" it other) '(Batman Jekyll) '(Robin Hyde)) + => '("Batman & Robin" "Jekyll & Hyde") + (-zip-with #'cons '(nil) '(nil)) => '((nil)) + (-zip-with #'cons '(nil) '(nil nil)) => '((nil)) + (-zip-with #'cons '(nil nil) '(nil)) => '((nil)) + (-zip-with #'cons '(nil nil) '(nil nil)) => '((nil) (nil)) + (--zip-with (cons it other) () ()) => () + (--zip-with (cons it other) () '(nil)) => () + (--zip-with (cons it other) '(nil) '()) => () + (--zip-with (cons it other) '(nil) '(nil)) => '((nil)) + (--zip-with (cons it other) '(nil) '(nil nil)) => '((nil)) + (--zip-with (cons it other) '(nil nil) '(nil)) => '((nil)) + (--zip-with (cons it other) '(nil nil) '(nil nil)) => '((nil) (nil)) + (-zip-with #'signal () ()) => () + (-zip-with #'signal '(arith-error) ()) => () + (-zip-with #'signal () '(())) => () + (-zip-with #'signal '(arith-error) '(())) !!> (arith-error)) + + (defexamples -zip-pair + (-zip-pair '(1 2 3 4) '(5 6 7)) => '((1 . 5) (2 . 6) (3 . 7)) + (-zip-pair '(1 2 3) '(4 5 6)) => '((1 . 4) (2 . 5) (3 . 6)) + (-zip-pair '(1 2) '(3)) => '((1 . 3)) + (-zip-pair () ()) => () + (-zip-pair '(0) ()) => () + (-zip-pair () '(0)) => () + (-zip-pair '(1 2 3 4) '(4 5 6)) => '((1 . 4) (2 . 5) (3 . 6)) + (-zip-pair '(1 2 3) '(4 5 6 7)) => '((1 . 4) (2 . 5) (3 . 6)) + (with-no-warnings (-zip-pair '(1 2 3 4) '(5 6 7) '(8 9))) + => '((1 5 8) (2 6 9)) + (with-no-warnings (-zip-pair '(1 2 3) '(4 5 6) '(7 8 9))) + => '((1 4 7) (2 5 8) (3 6 9)) + (with-no-warnings (-zip-pair '(1 2 3))) => '((1) (2) (3)) + (with-no-warnings (-zip-pair)) => () + (with-no-warnings (-zip-pair ())) => () + (with-no-warnings (-zip-pair '(0))) => '((0)) + (with-no-warnings (-zip-pair '(0 1))) => '((0) (1)) + (with-no-warnings (-zip-pair () () ())) => () + (with-no-warnings (-zip-pair '(0) () ())) => () + (with-no-warnings (-zip-pair () '(0) ())) => () + (with-no-warnings (-zip-pair () () '(0))) => () + (with-no-warnings (-zip-pair '(0) '(1) ())) => () + (with-no-warnings (-zip-pair '(0) () '(1))) => () + (with-no-warnings (-zip-pair () '(0) '(1))) => () + (with-no-warnings (-zip-pair '(0) '(1) '(2))) => '((0 1 2)) + (with-no-warnings (-zip-pair '(0 1) '(2) '(3))) => '((0 2 3)) + (with-no-warnings (-zip-pair '(0) '(1 2) '(3))) => '((0 1 3)) + (with-no-warnings (-zip-pair '(0) '(1) '(2 3))) => '((0 1 2)) + (with-no-warnings (-zip-pair '(0 1) '(2 3) '(4))) => '((0 2 4)) + (with-no-warnings (-zip-pair '(0 1) '(2) '(3 4))) => '((0 2 3)) + (with-no-warnings (-zip-pair '(0) '(1 2) '(3 4))) => '((0 1 3)) + (with-no-warnings (-zip-pair '(0 1) '(2 3) '(4 5))) => '((0 2 4) (1 3 5)) + (with-no-warnings (-zip-pair '(0 1) '(2 3 4) '(5))) => '((0 2 5))) (defexamples -zip-lists (-zip-lists '(1 2 3) '(4 5 6)) => '((1 4) (2 5) (3 6)) @@ -1486,15 +1641,173 @@ related predicates." (-zip-lists '(1 2) '(3 4 5) '(6)) => '((1 3 6)) (-zip-lists '(1 2 3 4) '(4 5 6)) => '((1 4) (2 5) (3 6)) (-zip-lists '(1 2 3) '(4 5 6) '(7 8 9)) => '((1 4 7) (2 5 8) (3 6 9)) - (-zip-lists) => nil) + (-zip-lists) => () + (-zip-lists ()) => () + (-zip-lists '(0)) => '((0)) + (-zip-lists '(0 1)) => '((0) (1)) + (-zip-lists '(0 1 2)) => '((0) (1) (2)) + (-zip-lists () ()) => () + (-zip-lists '(0) ()) => () + (-zip-lists () '(0)) => () + (-zip-lists () () ()) => () + (-zip-lists '(0) () ()) => () + (-zip-lists () '(0) ()) => () + (-zip-lists () () '(0)) => () + (-zip-lists '(0) '(1) ()) => () + (-zip-lists '(0) () '(1)) => () + (-zip-lists () '(0) '(1)) => () + (-zip-lists '(0) '(1) '(2)) => '((0 1 2)) + (-zip-lists '(0 1) '(2) '(3)) => '((0 2 3)) + (-zip-lists '(0) '(1 2) '(3)) => '((0 1 3)) + (-zip-lists '(0) '(1) '(2 3)) => '((0 1 2)) + (-zip-lists '(0 1) '(2 3) '(4)) => '((0 2 4)) + (-zip-lists '(0 1) '(2) '(3 4)) => '((0 2 3)) + (-zip-lists '(0) '(1 2) '(3 4)) => '((0 1 3)) + (-zip-lists '(0 1) '(2 3) '(4 5)) => '((0 2 4) (1 3 5))) + + (defexamples -zip-lists-fill + (-zip-lists-fill 0 '(1 2) '(3 4 5) '(6)) => '((1 3 6) (2 4 0) (0 5 0)) + (-zip-lists-fill 0 '(1 2) '(3 4) '(5 6)) => '((1 3 5) (2 4 6)) + (-zip-lists-fill 0 '(1 2 3) ()) => '((1 0) (2 0) (3 0)) + (-zip-lists-fill 0) => () + (-zip-lists-fill 0 ()) => () + (-zip-lists-fill 0 '(1)) => '((1)) + (-zip-lists-fill 0 '(1 2)) => '((1) (2)) + (-zip-lists-fill 0 '(1 2 3)) => '((1) (2) (3)) + (-zip-lists-fill 0 () ()) => () + (-zip-lists-fill 0 '(1) ()) => '((1 0)) + (-zip-lists-fill 0 () '(1)) => '((0 1)) + (-zip-lists-fill 0 '(1) '(2)) => '((1 2)) + (-zip-lists-fill 0 '(1 2) ()) => '((1 0) (2 0)) + (-zip-lists-fill 0 () '(1 2)) => '((0 1) (0 2)) + (-zip-lists-fill 0 () '(1 2 3)) => '((0 1) (0 2) (0 3)) + (-zip-lists-fill 0 '(1 2) '(3)) => '((1 3) (2 0)) + (-zip-lists-fill 0 '(1) '(2 3)) => '((1 2) (0 3)) + (-zip-lists-fill 0 () () ()) => () + (-zip-lists-fill 0 '(1) () ()) => '((1 0 0)) + (-zip-lists-fill 0 () '(1) ()) => '((0 1 0)) + (-zip-lists-fill 0 () () '(1)) => '((0 0 1)) + (-zip-lists-fill 0 '(1 2) () ()) => '((1 0 0) (2 0 0)) + (-zip-lists-fill 0 () '(1 2) ()) => '((0 1 0) (0 2 0)) + (-zip-lists-fill 0 () () '(1 2)) => '((0 0 1) (0 0 2))) + + (defexamples -zip + (-zip '(1 2 3 4) '(5 6 7) '(8 9)) => '((1 5 8) (2 6 9)) + (-zip '(1 2 3) '(4 5 6) '(7 8 9)) => '((1 4 7) (2 5 8) (3 6 9)) + (-zip '(1 2 3)) => '((1) (2) (3)) + (-zip) => () + (-zip ()) => () + (-zip '(0)) => '((0)) + (-zip '(0 1)) => '((0) (1)) + (with-no-warnings (-zip () ())) => () + (with-no-warnings (-zip '(0) ())) => () + (with-no-warnings (-zip () '(0))) => () + (with-no-warnings (-zip '(1 2 3 4) '(4 5 6))) => '((1 . 4) (2 . 5) (3 . 6)) + (with-no-warnings (-zip '(1 2 3) '(4 5 6 7))) => '((1 . 4) (2 . 5) (3 . 6)) + (-zip () () ()) => () + (-zip '(0) () ()) => () + (-zip () '(0) ()) => () + (-zip () () '(0)) => () + (-zip '(0) '(1) ()) => () + (-zip '(0) () '(1)) => () + (-zip () '(0) '(1)) => () + (-zip '(0) '(1) '(2)) => '((0 1 2)) + (-zip '(0 1) '(2) '(3)) => '((0 2 3)) + (-zip '(0) '(1 2) '(3)) => '((0 1 3)) + (-zip '(0) '(1) '(2 3)) => '((0 1 2)) + (-zip '(0 1) '(2 3) '(4)) => '((0 2 4)) + (-zip '(0 1) '(2) '(3 4)) => '((0 2 3)) + (-zip '(0) '(1 2) '(3 4)) => '((0 1 3)) + (-zip '(0 1) '(2 3) '(4 5)) => '((0 2 4) (1 3 5)) + (-zip '(0 1) '(2 3 4) '(5)) => '((0 2 5))) (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))) + (-zip-fill 0 '(1 2 3) '(4 5)) => '((1 . 4) (2 . 5) (3 . 0)) + (-zip-fill 0 '() '(1 2 3)) => '((0 . 1) (0 . 2) (0 . 3)) + (-zip-fill 0 '(1 2) '(3 4) '(5 6)) => '((1 3 5) (2 4 6)) + (-zip-fill 0 '(1 2) '(3 4 5) '(6)) => '((1 3 6) (2 4 0) (0 5 0)) + (-zip-fill 0) => () + (-zip-fill 0 ()) => () + (-zip-fill 0 '(1)) => '((1)) + (-zip-fill 0 '(1 2)) => '((1) (2)) + (-zip-fill 0 '(1 2 3)) => '((1) (2) (3)) + (-zip-fill 0 () ()) => () + (-zip-fill 0 '(1) ()) => '((1 . 0)) + (-zip-fill 0 () '(1)) => '((0 . 1)) + (-zip-fill 0 '(1) '(2)) => '((1 . 2)) + (-zip-fill 0 '(1 2) ()) => '((1 . 0) (2 . 0)) + (-zip-fill 0 () '(1 2)) => '((0 . 1) (0 . 2)) + (-zip-fill 0 '(1 2 3) ()) => '((1 . 0) (2 . 0) (3 . 0)) + (-zip-fill 0 () '(1 2 3)) => '((0 . 1) (0 . 2) (0 . 3)) + (-zip-fill 0 '(1 2) '(3)) => '((1 . 3) (2 . 0)) + (-zip-fill 0 '(1) '(2 3)) => '((1 . 2) (0 . 3)) + (-zip-fill 0 () () ()) => () + (-zip-fill 0 '(1) () ()) => '((1 0 0)) + (-zip-fill 0 () '(1) ()) => '((0 1 0)) + (-zip-fill 0 () () '(1)) => '((0 0 1)) + (-zip-fill 0 '(1 2) () ()) => '((1 0 0) (2 0 0)) + (-zip-fill 0 () '(1 2) ()) => '((0 1 0) (0 2 0)) + (-zip-fill 0 () () '(1 2)) => '((0 0 1) (0 0 2))) + + (defexamples -unzip-lists + (-unzip-lists (-zip-lists '(1 2) '(3 4) '(5 6))) => '((1 2) (3 4) (5 6)) + (-unzip-lists '((1 2 3) (4 5) (6 7) (8 9))) => '((1 4 6 8) (2 5 7 9)) + (-unzip-lists '((1 2 3) (4 5 6))) => '((1 4) (2 5) (3 6)) + (-unzip-lists ()) => () + (-unzip-lists '(())) => () + (-unzip-lists '((1))) => '((1)) + (-unzip-lists '((1 2))) => '((1) (2)) + (-unzip-lists '((1 2 3))) => '((1) (2) (3)) + (-unzip-lists '(() ())) => () + (-unzip-lists '((1) ())) => () + (-unzip-lists '(() (1))) => () + (-unzip-lists '((1) (2))) => '((1 2)) + (-unzip-lists '((1 2) (3))) => '((1 3)) + (-unzip-lists '((1) (2 3))) => '((1 2)) + (-unzip-lists '((1 2) (3 4))) => '((1 3) (2 4)) + (-unzip-lists '(() () ())) => () + (-unzip-lists '((1) () ())) => () + (-unzip-lists '(() (1) ())) => () + (-unzip-lists '(() () (1))) => () + (-unzip-lists '((1) (2) ())) => () + (-unzip-lists '((1) () (2))) => () + (-unzip-lists '(() (1) (2))) => () + (-unzip-lists '((1) (2) (3))) => '((1 2 3)) + (-unzip-lists '((1 2) (3) (4))) => '((1 3 4)) + (-unzip-lists '((1) (2 3) (4))) => '((1 2 4)) + (-unzip-lists '((1) (2) (3 4))) => '((1 2 3)) + (-unzip-lists '((1 2) (3 4) (5 6))) => '((1 3 5) (2 4 6)) + (-unzip-lists '((1 2 3) (4 5 6) (7 8 9))) => '((1 4 7) (2 5 8) (3 6 9))) (defexamples -unzip - (-unzip (-zip '(1 2 3) '(a b c) '("e" "f" "g"))) => '((1 2 3) (a b c) ("e" "f" "g")) - (-unzip '((1 2) (3 4) (5 6) (7 8) (9 10))) => '((1 3 5 7 9) (2 4 6 8 10)) - (-unzip '((1 2) (3 4))) => '((1 . 3) (2 . 4))) + (-unzip (-zip '(1 2) '(3 4) '(5 6))) => '((1 . 2) (3 . 4) (5 . 6)) + (-unzip '((1 2 3) (4 5 6))) => '((1 . 4) (2 . 5) (3 . 6)) + (-unzip '((1 2 3) (4 5) (6 7) (8 9))) => '((1 4 6 8) (2 5 7 9)) + (-unzip ()) => () + (-unzip '(())) => () + (-unzip '((1))) => '((1)) + (-unzip '((1 2))) => '((1) (2)) + (-unzip '((1 2 3))) => '((1) (2) (3)) + (-unzip '(() ())) => () + (-unzip '((1) ())) => () + (-unzip '(() (1))) => () + (-unzip '((1) (2))) => '((1 . 2)) + (-unzip '((1 2) (3))) => '((1 . 3)) + (-unzip '((1) (2 3))) => '((1 . 2)) + (-unzip '((1 2) (3 4))) => '((1 . 3) (2 . 4)) + (-unzip '(() () ())) => () + (-unzip '((1) () ())) => () + (-unzip '(() (1) ())) => () + (-unzip '(() () (1))) => () + (-unzip '((1) (2) ())) => () + (-unzip '((1) () (2))) => () + (-unzip '(() (1) (2))) => () + (-unzip '((1) (2) (3))) => '((1 2 3)) + (-unzip '((1 2) (3) (4))) => '((1 3 4)) + (-unzip '((1) (2 3) (4))) => '((1 2 4)) + (-unzip '((1) (2) (3 4))) => '((1 2 3)) + (-unzip '((1 2) (3 4) (5 6))) => '((1 3 5) (2 4 6)) + (-unzip '((1 2 3) (4 5 6) (7 8 9))) => '((1 4 7) (2 5 8) (3 6 9))) (defexamples -pad (-pad 0 '()) => '(()) @@ -2344,26 +2657,28 @@ or readability." (funcall (-fixfn #'sin #'approx=) 0.1) => '(halted . t)) (defexamples -prodfn - (funcall (-prodfn '1+ '1- 'number-to-string) '(1 2 3)) => '(2 1 "3") - (-map (-prodfn '1+ '1-) '((1 2) (3 4) (5 6) (7 8))) => '((2 1) (4 3) (6 5) (8 7)) - (apply '+ (funcall (-prodfn 'length 'string-to-number) '((1 2 3) "15"))) => 18 - (let ((f '1+) - (g '1-) - (ff 'string-to-number) - (gg 'length) + (funcall (-prodfn #'1+ #'1- #'number-to-string) '(1 2 3)) => '(2 1 "3") + (-map (-prodfn #'1- #'1+) '((1 2) (3 4) (5 6))) => '((0 3) (2 5) (4 7)) + (apply #'+ (funcall (-prodfn #'length #'string-to-number) '((t) "5"))) => 6 + (let ((f #'1+) + (g #'1-) + (ff #'string-to-number) + (gg #'length) (input '(1 2)) (input2 "foo") (input3 '("10" '(1 2 3)))) (and (equal (funcall (-prodfn f g) input) - (funcall (-juxt (-compose f (-partial 'nth 0)) (-compose g (-partial 'nth 1))) input)) + (funcall (-juxt (-compose f #'car) (-compose g #'cadr)) + input)) (equal (funcall (-compose (-prodfn f g) (-juxt ff gg)) input2) (funcall (-juxt (-compose f ff) (-compose g gg)) input2)) - (equal (funcall (-compose (-partial 'nth 0) (-prodfn f g)) input) - (funcall (-compose f (-partial 'nth 0)) input)) - (equal (funcall (-compose (-partial 'nth 1) (-prodfn f g)) input) - (funcall (-compose g (-partial 'nth 1)) input)) + (equal (funcall (-compose (-partial #'nth 0) (-prodfn f g)) input) + (funcall (-compose f (-partial #'nth 0)) input)) + (equal (funcall (-compose (-partial #'nth 1) (-prodfn f g)) input) + (funcall (-compose g (-partial #'nth 1)) input)) (equal (funcall (-compose (-prodfn f g) (-prodfn ff gg)) input3) - (funcall (-prodfn (-compose f ff) (-compose g gg)) input3)))) => t)) + (funcall (-prodfn (-compose f ff) (-compose g gg)) input3)))) + => t)) (ert-deftest dash--member-fn () "Test `dash--member-fn'." @@ -2488,4 +2803,9 @@ or readability." (3 5 4) (3 4 5))))) +(ert-deftest dash--length= () + "Test `dash--length='." + (dotimes (n 10) + (should (dash--length= (make-list n nil) n)))) + ;;; examples.el ends here