omdl  v1.0
OpenSCAD Mechanical Design Library
iterable_operate.scad
Go to the documentation of this file.
1 //! Iterable data type operations.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2015-2026
6 
7  \copyright
8 
9  This file is part of [omdl] (https://github.com/royasutton/omdl),
10  an OpenSCAD mechanical design library.
11 
12  The \em omdl is free software; you can redistribute it and/or modify
13  it under the terms of the [GNU Lesser General Public License]
14  (http://www.gnu.org/licenses/lgpl.html) as published by the Free
15  Software Foundation; either version 2.1 of the License, or (at
16  your option) any later version.
17 
18  The \em omdl is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  Lesser General Public License for more details.
22 
23  You should have received a copy of the GNU Lesser General Public
24  License along with the \em omdl; if not, write to the Free Software
25  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26  02110-1301, USA; or see <http://www.gnu.org/licenses/>.
27 
28  \details
29 
30  \amu_define group_name (Iterable Operations)
31  \amu_define group_brief (Operations for iterable data types.)
32 
33  \amu_include (include/amu/doxyg_init_pd_gds_ipg.amu)
34 *******************************************************************************/
35 
36 // auto-tests (add to test results page)
37 /***************************************************************************//**
38  \amu_include (include/amu/validate_log.amu)
39  \amu_include (include/amu/validate_results.amu)
40 *******************************************************************************/
41 
42 // group(s) begin (test summary and includes-required)
43 /***************************************************************************//**
44  \amu_include (include/amu/doxyg_define_in_parent_open.amu)
45  \amu_include (include/amu/validate_summary.amu)
46  \amu_include (include/amu/includes_required.amu)
47 *******************************************************************************/
48 
49 // member-wide reference definitions
50 /***************************************************************************//**
51  \amu_define group_references
52  (
53  [search]: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#search
54  )
55 *******************************************************************************/
56 
57 // member-wide documentation and conventions
58 /***************************************************************************//**
59  \addtogroup \amu_eval(${group})
60  \details
61  \anchor \amu_eval(${group})_conventions
62  \par Conventions
63 
64  - The match-value parameter is always \p mv.
65  - The match-count parameter is always \p mc. A value of 0 (or any value
66  <= 0) means 'match all occurrences'. A positive value \p mc means
67  'match at most \p mc occurrences'.
68  - The insert-value parameter in shift_ci() is \p iv, not \p i.
69  The parameter \p i is reserved for index positions throughout the group.
70  - \p mv takes precedence over \p i in functions that accept both: when
71  \p mv is defined, the match is by value; \p i provides an optional
72  secondary element index for structured-element matching.
73  - Functions that return a modified copy of \p v never modify \p v in place.
74  - When \p v is not iterable, most functions return \p v unchanged.
75  Exceptions are documented individually.
76 *******************************************************************************/
77 
78 //----------------------------------------------------------------------------//
79 // members
80 //----------------------------------------------------------------------------//
81 
82 //! Returns an element from an iterable if it exists, or a default value if not.
83 /***************************************************************************//**
84  \param v <iterable> An iterable value.
85  \param i <integer> An element index.
86  \param d <value> A default value.
87 
88  \returns (1) <value> \c v[i] if it is defined, or \p d otherwise.
89 *******************************************************************************/
90 function defined_e_or
91 (
92  v,
93  i,
94  d
95 ) = !is_iterable(v) ? d
96  : !is_undef( v[i] ) ? v[i]
97  : d;
98 
99 //! Returns the list element or scalar numeric value if defined, otherwise returns the default value.
100 /***************************************************************************//**
101  \param v <value> A value.
102  \param i <integer> An element index.
103  \param d <value> A default value.
104 
105  \returns (1) <number> \c v if it is a scalar numeric value;
106  (2) <value> \c v[i] if it is defined, otherwise the
107  default value \p d.
108 *******************************************************************************/
109 function defined_eon_or
110 (
111  v,
112  i,
113  d
114 ) = is_num(v) ? v
115  : !is_iterable(v) ? d
116  : !is_undef( v[i] ) ? v[i]
117  : d;
118 
119 //! Returns the list element or scalar numeric or boolean value if defined, otherwise returns the default value.
120 /***************************************************************************//**
121  \param v <value> A value.
122  \param i <integer> An element index.
123  \param d <value> A default value.
124 
125  \returns (1) <value> \c v if it is a scalar numeric or boolean value;
126  (2) <value> \c v[i] if it is defined, otherwise the
127  default value \p d.
128 *******************************************************************************/
129 function defined_eonb_or
130 (
131  v,
132  i,
133  d
134 ) = (is_num(v) || is_bool(v)) ? v
135  : !is_iterable(v) ? d
136  : !is_undef( v[i] ) ? v[i]
137  : d;
138 
139 //! Return the first defined specified element in a list of lists, otherwise returns the given default value.
140 /***************************************************************************//**
141  \param v <value> A list of \p n elements lists.
142  \param i <integer> The specified element index.
143  \param d <value> A default value.
144 
145  \returns (1) <value> for the given \p v, a list of \p n lists,
146  return the first element v[j][i] that is defined where
147  j = [0 : n], otherwise the default value \p d.
148 *******************************************************************************/
149 function defined_fle_or
150 (
151  v,
152  i,
153  d
154 ) = !is_iterable(v) ? d
155  : is_empty(v) ? d
156  : let ( w = first ( v ) )
157  !is_undef( w[i] ) ? w[i]
158  : defined_fle_or( v=tailn(v), i=i, d=d );
159 
160 //! Returns an element from an iterable if it exists and is a iterable, otherwise returns a default value.
161 /***************************************************************************//**
162  \param v <value> A value.
163  \param i <integer> An element index.
164  \param d <value> A default value.
165  \param n <integer> The optional expected element length.
166 
167  \returns (1) \c v[i], a <list-n> if the element is iterable of
168  length \p n (or <list> if \p n is unspecified),
169  (2) or the default value \p d if the element is not defined.
170 *******************************************************************************/
171 function defined_ei_or
172 (
173  v,
174  i,
175  d,
176  n
177 ) = !is_iterable(v) ? d
178  : is_iterable( v[i] )
179  ? is_undef( n ) ? v[i]
180  : (len( v[i] ) == n) ? v[i]
181  : d
182  : d;
183 
184 //! Find all occurrences of a match value in an iterable value.
185 /***************************************************************************//**
186  \param mv <value> A match value.
187  \param v <iterable> An iterable value.
188 
189  \returns (1) <list> A list of indexes where elements match \p mv.
190  (2) Returns \b empty_lst when no element of \p v matches
191  \p mv or when \p v is not iterable.
192 *******************************************************************************/
193 function find_all
194 (
195  mv,
196  v
197 ) = !is_iterable(v) ? empty_lst
198  : [ for (j = [0 : len(v)-1]) if (v[j] == mv) j ];
199 
200 //! Find the occurrences of a match value in an iterable value.
201 /***************************************************************************//**
202  \param mv <value> A match value.
203  \param v <iterable> An iterable value.
204  \param c <integer> A match count.
205  For `(c >= 1)`, return the first \p c matches.
206  For `(c <= 0)`, return all matches.
207  \param i <integer> The secondary element index to match for when
208  the elements of \p v are themselves iterable elements.
209 
210  \param i1 <integer> The element index of \p v where the search begins.
211  \param i2 <integer> The element index of \p v where the search ends.
212 
213  \returns (1) <list> A list of indexes where elements match \p mv.
214  (2) Returns \b empty_lst when no element of \p v matches
215  \p mv or when \p v is not iterable.
216 
217  \details
218 
219  The use-cases for find() and [search]\‍() are summarized in the
220  following tables.
221 
222  \b Find:
223 
224  | mv / v | string | list of scalars | list of iterables |
225  |:-------------------:|:------:|:-----------------:|:-------------------:|
226  | scalar | | (a) | (b) see note 1 |
227  | string | (c) | | (b) see note 1 |
228  | list of scalars | | | (b) see note 1 |
229  | list of iterables | | | (b) see note 1 |
230 
231  \b Search:
232 
233  | mv / v | string | list of scalars | list of iterables |
234  |:-------------------:|:------:|:-----------------:|:-------------------:|
235  | scalar | | (a) | (b) |
236  | string | (d) | invalid | (e) see note 2 |
237  | list of scalars | | (f) | (g) |
238  | list of iterables | | | (g) |
239 
240  \b Key:
241 
242  \li (a) Identify each element of \p v that equals \p mv.
243  \li (b) Identify each element of \p v where \p mv equals the element at
244  the specified column index, \p i, of each iterable value in \p v.
245  \li (c) If, and only if, \p mv is a single character, identify each
246  character in \p v that equals \p mv.
247  \li (d) For each character of \p mv, identify where it exists in \p v.
248  \b empty_lst is returned for each character of \p mv absent from \p v.
249  \li (e) For each character of \p mv, identify where it exists in \p v
250  either as a numeric value or as a character at the specified column
251  index, \p i.
252  \b empty_lst is returned for each character of \p mv absent from \p v.
253  \li (f) For each scalar of \p mv, identify where it exists in \p v.
254  \b empty_lst is returned for each scalar of \p mv absent from \p v.
255  \li (g) For each element of \p mv, identify where it equals the element
256  at the specified column index, \p i, of each iterable value in \p v.
257  \b empty_lst is returned for each element of \p mv absent from \p v
258  in the specified column index.
259 
260  \note \b 1: When \p i is specified, that element column is compared.
261  Otherwise, the entire element is compared. Functions find()
262  and [search]\‍() behave differently in this regard.
263  \note \b 2: Invalid use combination when any element of \p v is a
264  string. However, an element that is a list of one or more
265  strings is valid. In which case, only the first character of
266  each string element is considered.
267 
268  \amu_eval (${group_references})
269 *******************************************************************************/
270 function find
271 (
272  mv,
273  v,
274  c = 1,
275  i,
276  i1 = 0,
277  i2
278 ) = !is_iterable(v) ? empty_lst // not iterable
279  : (!is_undef(i2) && (i1 > i2)) ? empty_lst // at upper index
280  : (i1 > len(v)-1) ? empty_lst // at end of list
281  : ((is_undef(i) && (v[i1] == mv)) || (v[i1][i] == mv)) ? // match method
282  (
283  (c == 1) ? [i1] // one or all
284  : concat(i1, find(mv, v, c-1, i, i1+1, i2)) // add to list
285  )
286  : find(mv, v, c, i, i1+1, i2); // no match, cont.
287 
288 //! Count all occurrences of a match value in an iterable value.
289 /***************************************************************************//**
290  \param mv <value> A match value.
291  \param v <iterable> An iterable value.
292  \param s <boolean> Element matching search method.
293  \param i <integer> The secondary element index to match for when
294  the elements of \p v are themselves iterable elements.
295 
296  \returns (1) <integer> The number of times \p mv occurs in the list.
297 
298  \details
299 
300  When \p s == \b true, [search]\‍() is used to match elements. When
301  \p s == false, find() is used.
302 
303  \amu_eval (${group_references})
304 *******************************************************************************/
305 function count
306 (
307  mv,
308  v,
309  s = true,
310  i
311 ) = (s == false) ? len(find(mv, v, 0, i))
312  : len(merge_s(search(mv, v, 0, i)));
313 
314 //! Check for the existence of a match value in an iterable value.
315 /***************************************************************************//**
316  \param mv <value> A match value.
317  \param v <iterable> An iterable value.
318  \param s <boolean> Element matching search method.
319  \param i <integer> The secondary element index to match for when
320  the elements of \p v are themselves iterable elements.
321 
322  \returns (1) <boolean> \b true when \p mv exists in the list and
323  \b false otherwise.
324 
325  \details
326 
327  When `s == true`, [search]\‍() is used to match elements. When `s ==
328  false`, find() is used.
329 
330  \amu_eval (${group_references})
331 *******************************************************************************/
332 function exists
333 (
334  mv,
335  v,
336  s = true,
337  i
338 ) = (s == false) ? (find(mv, v, 1, i) != empty_lst)
339  : (strip(search(mv, v, 1, i)) != empty_lst);
340 
341 //! Test if an element exists at a specified index of an iterable value.
342 /***************************************************************************//**
343  \param i <integer> An element index.
344  \param v <iterable> An iterable value.
345 
346  \returns (1) <boolean> \b true when the element \p v[i], exists and
347  \b false otherwise.
348  (2) Returns \b undef when \p i is not an number.
349 
350  \note This functions does not consider the value of the element
351  at the index position, but rather if an element exists at
352  the index position \p i.
353 *******************************************************************************/
354 function exists_e
355 (
356  i,
357  v
358 ) = !is_number( i ) ? undef
359  : (i < 0) ? false
360  : !is_iterable( v ) ? false
361  : (len(v) > i);
362 
363 //! Return the first element of an iterable value.
364 /***************************************************************************//**
365  \param v <iterable> An iterable value.
366 
367  \returns (1) <value> The first element of \p v.
368  (2) Returns \b undef when \p v is not defined, is not
369  iterable, or is empty.
370 
371  \details
372 
373  \note Value may also be a range to obtain its \em start value.
374 *******************************************************************************/
375 function first( v ) = v[0];
376 
377 //! Return the second element of an iterable value.
378 /***************************************************************************//**
379  \param v <iterable> An iterable value.
380 
381  \returns (1) <value> The second element of \p v.
382  (2) Returns \b undef when \p v is not defined, is not
383  iterable, or is empty.
384 
385  \details
386 
387  \note Value may also be a range to obtain its \em step value.
388 *******************************************************************************/
389 function second( v ) = v[1];
390 
391 //! Return the third element of an iterable value.
392 /***************************************************************************//**
393  \param v <iterable> An iterable value.
394 
395  \returns (1) <value> The third element of \p v.
396  (2) Returns \b undef when \p v is not defined, is not
397  iterable, or is empty.
398 
399  \details
400 
401  \note Value may also be a range to obtain its \em end value.
402 *******************************************************************************/
403 function third( v ) = v[2];
404 
405 //! Return the last element of an iterable value.
406 /***************************************************************************//**
407  \param v <iterable> An iterable value.
408 
409  \returns (1) <value> The last element of \p v.
410  (2) Returns \b undef when \p v is not defined, is not
411  iterable, or is empty.
412 *******************************************************************************/
413 function last
414 (
415  v
416 ) = !is_iterable(v) ? undef
417  : v[len(v)-1];
418 
419 //! Return the middle element of an iterable value.
420 /***************************************************************************//**
421  \param v <iterable> An iterable value.
422 
423  \returns (1) <value> The middle element of \p v.
424  (2) Returns \b undef when \p v is not defined, is not
425  iterable, or is empty.
426 *******************************************************************************/
427 function middle
428 (
429  v
430 ) = !is_iterable(v) ? undef
431  : v[len(v)/2];
432 
433 //! Return a list containing the first two elements of an iterable value.
434 /***************************************************************************//**
435  \param v <iterable> An iterable value.
436 
437  \returns (1) <list> A list containing the first two elements of \p v.
438  (2) Returns \b undef when \p v is not defined, is not
439  iterable, is empty or has less than two elements
440 
441  \details
442 
443  \note Value may also be a range.
444 *******************************************************************************/
445 function first2
446 (
447  v
448 ) = !is_iterable(v) ? undef
449  : (len(v) < 2) ? undef
450  : [v[0], v[1]];
451 
452 //! Return a list containing the first three elements of an iterable value.
453 /***************************************************************************//**
454  \param v <iterable> An iterable value.
455 
456  \returns (1) <list> A list containing the first three elements of \p v.
457  (2) Returns \b undef when \p v is not defined, is not
458  iterable, is empty, or has less than three elements.
459 
460  \details
461 
462  \note Value may also be a range.
463 *******************************************************************************/
464 function first3
465 (
466  v
467 ) = !is_iterable(v) ? undef
468  : (len(v) < 3) ? undef
469  : [v[0], v[1], v[2]];
470 
471 //! Return a list containing the last two elements of an iterable value.
472 /***************************************************************************//**
473  \param v <iterable> An iterable value.
474 
475  \returns (1) <list> A list containing the last two elements of \p v.
476  (2) Returns \b undef when \p v is not defined, is not
477  iterable, is empty, or has less than two elements.
478 *******************************************************************************/
479 function last2
480 (
481  v
482 ) = !is_iterable(v) ? undef
483  : let( l = len(v) )
484  (l < 2) ? undef
485  : [v[l-2], v[l-1]];
486 
487 //! Return a list containing the last three elements of an iterable value.
488 /***************************************************************************//**
489  \param v <iterable> An iterable value.
490 
491  \returns (1) <list> A list containing the last three elements of \p v.
492  (2) Returns \b undef when \p v is not defined, is not
493  iterable, is empty, or has less than three elements.
494 *******************************************************************************/
495 function last3
496 (
497  v
498 ) = !is_iterable(v) ? undef
499  : let( l = len(v) )
500  (l < 3) ? undef
501  : [v[l-3], v[l-2], v[l-1]];
502 
503 //! Return a list containing the first \p n elements of an iterable value.
504 /***************************************************************************//**
505  \param v <iterable> An iterable value.
506  \param n <integer> The element count.
507 
508  \returns (1) <list> A list containing the first \p n elements of \p v.
509  (2) Returns \b undef when \p v is not defined, is not
510  iterable, or is empty.
511 
512  \details
513 
514  When \p n is greater than the length of the iterable \p v, the list
515  will stop at the last element of \p v.
516 *******************************************************************************/
517 function firstn
518 (
519  v,
520  n = 1
521 ) = !is_iterable(v) ? undef
522  : is_empty(v) ? undef
523  : n < 1 ? empty_lst
524  : let ( s = min(n-1, len(v)-1) )
525  [for (i = [0 : s]) v[i]];
526 
527 //! Return a list containing the last \p n elements of an iterable value.
528 /***************************************************************************//**
529  \param v <iterable> An iterable value.
530  \param n <integer> The element count.
531 
532  \returns (1) <list> A list containing the last \p n elements of \p v.
533  (2) Returns \b undef when \p v is not defined, is not
534  iterable, or is empty.
535 
536  \details
537 
538  When \p n is greater than the length of the iterable \p v, the list
539  will start at the first element of \p v.
540 *******************************************************************************/
541 function lastn
542 (
543  v,
544  n = 1
545 ) = !is_iterable(v) ? undef
546  : is_empty(v) ? undef
547  : n < 1 ? empty_lst
548  : let ( s = max(0, len(v)-n) )
549  [for (i = [s : len(v)-1]) v[i]];
550 
551 //! Return a list containing all but the last \p n elements of an iterable value.
552 /***************************************************************************//**
553  \param v <iterable> An iterable value.
554  \param n <integer> The element count.
555 
556  \returns (1) <list> A list containing all but the last \p n
557  elements of \p v.
558  (2) Returns \b empty_lst when \p v contains fewer than \p n
559  elements.
560  (3) Returns \b undef when \p v is not defined, is not
561  iterable, or is empty.
562 *******************************************************************************/
563 function headn
564 (
565  v,
566  n = 1
567 ) = !is_iterable(v) ? undef
568  : is_empty(v) ? undef
569  : (n >= len(v)) ? empty_lst
570  : let ( s = min(len(v)-1, len(v)-1-n) )
571  [for (i = [0 : s]) v[i]];
572 
573 //! Return a list containing all but the first \p n elements of an iterable value.
574 /***************************************************************************//**
575  \param v <iterable> An iterable value.
576  \param n <integer> The element count.
577 
578  \returns (1) <list> A list containing all but the first \p n
579  elements of \p v.
580  (2) Returns \b empty_lst when \p v contains fewer than \p n
581  elements.
582  (3) Returns \b undef when \p v is not defined, is not
583  iterable, or is empty.
584 *******************************************************************************/
585 function tailn
586 (
587  v,
588  n = 1
589 ) = !is_iterable(v) ? undef
590  : is_empty(v) ? undef
591  : (n >= len(v)) ? empty_lst
592  : [for (i = [max(0, n) : len(v)-1]) v[i]];
593 
594 //! Reverse the elements of an iterable value.
595 /***************************************************************************//**
596  \param v <iterable> An iterable value.
597 
598  \returns (1) <list> A list containing the elements of \p v in
599  reversed order.
600  (2) Returns \b empty_lst when \p v is empty.
601  (3) Returns \b undef when \p v is not defined or is not iterable.
602 *******************************************************************************/
603 function reverse
604 (
605  v
606 ) = !is_iterable(v) ? undef
607  : is_empty(v) ? empty_lst
608  : [for (i = [len(v)-1 : -1 : 0]) v[i]];
609 
610 //! Circularly shift the elements of an iterable, with an optional element drop.
611 /***************************************************************************//**
612  \param v <iterable> An iterable value.
613  \param n <integer> The element shift count.
614  \param r <boolean> Shift the elements to the right (or left).
615  \param d <boolean> Drop elements outside of iterable value shift window.
616 
617  \returns (1) <list> A list containing the elements of \p v shifted
618  by \p n elements.
619  (2) Returns \b undef when \p v is not defined or is not iterable.
620 
621  \details
622 
623  The shift count \p n may be positive or negative.
624 *******************************************************************************/
625 function shift_cd
626 (
627  v,
628  n = 0,
629  r = true,
630  d = false
631 ) = !is_iterable(v) ? undef
632  : let
633  (
634  l = len(v),
635  s = abs(n), // absolute magnitude
636  m = s % l, // circular magnitude
637  p = (n > 0) ? r : !r // shift direction
638  )
639  // drop-shift and shift magnitude greater than element count
640  ( d && s > l-1 ) ? empty_lst
641  : ( p ) ?
642  // shift right
643  [ if (m && !d) for (i = [l-m : l-1]) v[i], for (i = [0 : l-1-m]) v[i] ]
644  // shift left
645  : [ for (i = [m : l-1]) v[i], if (m && !d) for (i = [0 : m-1]) v[i] ];
646 
647 //! Shift-in a value to the elements of a given iterable value.
648 /***************************************************************************//**
649  \param v <iterable> The iterable value.
650  \param n <integer> The element shift count.
651  \param r <boolean> Shift the elements to the right (or left).
652  \param i <value> The value to shit-in on the left or right.
653 
654  \returns (1) <list> A list containing the elements of \p v shifted
655  by \p n elements with the value \p i inserted on the
656  left or right side of the given iterable value.
657  (2) Returns \b undef when \p v is not defined or is not iterable.
658 
659  \details
660 
661  The shift count \p n may be positive or negative.
662 *******************************************************************************/
663 function shift_ci
664 (
665  v,
666  n = 0,
667  r = true,
668  i
669 ) = !is_iterable(v) ? undef
670  : let
671  (
672  l = len(v),
673  s = abs(n), // absolute magnitude
674  m = s % l, // circular magnitude
675  d = (n > 0) ? r : !r // shift direction
676  )
677  // shift greater than elements
678  ( s > l-1 ) ? is_undef(i) ? consts(l, u=true) : consts(l, i)
679  // shift direction
680  : ( d ) ?
681  // shift right
682  [ if (m) for (j = [0 : s-1]) i, for (j = [0 : l-1-m]) v[j] ]
683  // shift left
684  : [ for (j = [m : l-1]) v[j], if (m) for (j = [0 : s-1]) i ];
685 
686 //! Select a range of elements from an iterable value.
687 /***************************************************************************//**
688  \param v <iterable> An iterable value.
689  \param i <range | list | integer> The index selection.
690 
691  \returns (1) <list> A list containing the selected elements.
692  (2) Returns \b undef when \p v is not defined, is not
693  iterable, or when \p i does not map to an element of \p v.
694  (3) Returns \b empty_lst when \p v is empty.
695 *******************************************************************************/
696 function select_r
697 (
698  v,
699  i
700 ) = (!is_iterable(v) || !all_defined(i)) ? undef
701  : is_empty(v) ? empty_lst
702  : ( !is_number(i) && !is_list(i) && !is_range(i) ) ? undef
703  : is_number(i) && !is_between(i, 0, len(v)-1) ? undef
704  : is_list(i) && ((min([for (y=i) y])<0) || (max([for (y=i) y])>(len(v)-1))) ? undef
705  : is_range(i) && ((min([for (y=i) y])<0) || (max([for (y=i) y])>(len(v)-1))) ? undef
706  : let ( s = is_number(i) ? [i] : i )
707  [for (j = [for (k=s) k]) v[j]];
708 
709 //! Return a list of all n-element sequential-subsets of an iterable value.
710 /***************************************************************************//**
711  \param v <iterable> An iterable value.
712  \param n <integer> The number of elements for each subset.
713  \param s <integer> The iteration step size.
714  \param w <boolean> Use wrap-at-end circular subset selection.
715 
716  \returns (1) <list-list> A list of all n-element sequential subsets
717  of \p v skipping \p s elements of \p v between each
718  subset selection.
719  (2) Returns \b empty_lst when \p v is empty, is not defined
720  or is not iterable.
721 
722  \details
723 
724  \b Example
725  \code{.C}
726  v = [1, 2, 3, 4];
727 
728  sequence_ns( v, 3, 1, false ); // [ [1,2,3], [2,3,4] ]
729  sequence_ns( v, 3, 1, true ); // [ [1,2,3], [2,3,4], [3,4,1], [4,1,2] ]
730  \endcode
731 *******************************************************************************/
732 function sequence_ns
733 (
734  v,
735  n = 1,
736  s = 1,
737  w = false
738 ) = is_empty(v) ? empty_lst
739  : [
740  for (i=[0 : s : (len(v)-((w == true) ? 1 : n)) ])
741  [
742  for (j=[i : (i+n-1)])
743  v[j % len(v)]
744  ]
745  ];
746 
747 //! Return all n-sized set combinations of iterable value.
748 /***************************************************************************//**
749  \param v <iterable> An iterable value.
750  \param n <integer> The set size size.
751 
752  \returns (1) <list-list> A list of all n-element combinations of \p v.
753  (2) Returns \b empty_lst when \p v is not iterable.
754 *******************************************************************************/
755 function combine_ns
756 (
757  v,
758  n
759 ) =
760  !is_iterable(v) ? empty_lst
761  : (n == 0) ? [empty_lst]
762  : (len(v) < n) ? empty_lst
763  : let
764  (
765  first = v[0],
766  rest = tailn(v),
767 
768  with_first =
769  [
770  for (c = combine_ns(rest, n - 1))
771  concat([first], c)
772  ],
773 
774  without_first = combine_ns(rest, n)
775  )
776  concat ( with_first, without_first );
777 
778 //! Return all ordered n-sized set permutations of iterable value.
779 /***************************************************************************//**
780  \param v <iterable> An iterable value.
781  \param n <integer> The set size size.
782 
783  \returns (1) <list-list> A list all ordered n-length permutations of
784  \p v without repetition of elements.
785  (2) Returns \b empty_lst when \p v is not iterable.
786 *******************************************************************************/
787 function permute_ns
788 (
789  v,
790  n
791 ) =
792  !is_iterable(v) ? empty_lst
793  : (n == 0) ? [empty_lst]
794  : (len(v) < n) ? empty_lst
795  : concat
796  (
797  [
798  for
799  (
800  i = [0 : len(v) - 1],
801  p = let
802  (
803  first = firstn(v, i),
804  rest = tailn(v, i+1)
805  )
806  permute_ns ( concat( first, rest ), n - 1 )
807  )
808  concat([v[i]], p)
809  ]
810  );
811 
812 //! Return all ordered n-size set permutations of iterable value with repetition allowed.
813 /***************************************************************************//**
814  \param v <iterable> An iterable value.
815  \param n <integer> The set size size.
816 
817  \returns (1) <list-list> A list all ordered n-length permutations of
818  \p v with element repetition allowed.
819  (2) Returns \b empty_lst when \p v is not iterable.
820 *******************************************************************************/
821 function permute_ns_r
822 (
823  v,
824  n
825 ) =
826  !is_iterable(v) ? empty_lst
827  : (n == 0) ? [empty_lst]
828  : concat
829  (
830  [
831  for ( i = v, p = permute_ns_r(v, n - 1) )
832  concat([i], p)
833  ]
834  );
835 
836 //! Append a value to each element of an iterable value.
837 /***************************************************************************//**
838  \param nv <value> A new value to append.
839  \param v <iterable> An iterable value.
840 
841  \param r <boolean> Reduce list element before appending.
842  \param j <boolean> Join each appendage as a separate list.
843 
844  \param l <boolean> Append new value to last element.
845 
846  \returns (1) <list> A list with \p nv appended to each element of \p v.
847  (2) Returns \b undef when \p v is not defined or is not iterable.
848 
849  \details
850 
851  Appending with `r == true` causes each element of \p nv to be
852  appended to the elements of each iterable value. When `r == false`,
853  each element of \p nv is appended to the iterable value itself. To
854  append a list of elements together as a list to \p v, enclose the
855  elements of \p nv with a second set of brackets.
856 
857  \b Example
858  \code{.C}
859  v1=[["a"], ["b"], ["c"], ["d"]];
860  v2=[1, 2, 3];
861 
862  echo( append_e( v2, v1 ) );
863  echo( append_e( v2, v1, r=false ) );
864  echo( append_e( v2, v1, j=false, l=false ) );
865  \endcode
866 
867  \b Result
868  \code{.C}
869  ECHO: [["a", 1, 2, 3], ["b", 1, 2, 3], ["c", 1, 2, 3], ["d", 1, 2, 3]]
870  ECHO: [[["a"], 1, 2, 3], [["b"], 1, 2, 3], [["c"], 1, 2, 3], [["d"], 1, 2, 3]]
871  ECHO: ["a", 1, 2, 3, "b", 1, 2, 3, "c", 1, 2, 3, "d"]
872  \endcode
873 
874 *******************************************************************************/
875 function append_e
876 (
877  nv,
878  v,
879  r = true,
880  j = true,
881  l = true
882 ) = !is_iterable(v) ? undef
883  // when 'v' is empty
884  : is_empty(v) ? ((j == true) ? [concat(nv)] : concat(nv))
885  // 'v' not empty
886  : let
887  ( // current element 'ce'
888  ce = (r == true) ? first(v) : [first(v)]
889  )
890  // last element of 'v'
891  (len(v) == 1) ?
892  (
893  (j == true && l == true ) ? [concat(ce, nv)]
894  : (j == true && l == false) ? [ce]
895  : (j == false && l == true ) ? concat(ce, nv)
896  : ce
897  )
898  : (j == true) ? concat( [concat(ce, nv)], append_e(nv, tailn(v), r, j, l) )
899  : concat( concat(ce, nv) , append_e(nv, tailn(v), r, j, l) );
900 
901 //! Append a value to the end or beginning of an iterable value.
902 /***************************************************************************//**
903  \param nv <value> The value to append.
904  \param v <iterable> An iterable value.
905  \param n <integer> The element shift count.
906  \param r <boolean> Shift the elements to the right (or left).
907 
908  \returns (1) <list> A list containing the elements of \p v shifted
909  by \p n elements with the value \p a appended the given
910  iterable value as specified.
911  (2) Returns \b undef when \p v is not defined or is not iterable.
912 
913  \details
914 
915  The shift count \p n may be positive or negative.
916 *******************************************************************************/
917 function append_v
918 (
919  nv,
920  v,
921  n = 0,
922  r = false
923 ) = !is_iterable(v) ? undef
924  : let
925  (
926  s = abs(n), // absolute magnitude
927  d = (n > 0) ? r : !r // shift direction
928  )
929  ( d ) ?
930  // shift right, prepend
931  [ for (j = [0 : s-1]) nv, for (j = v) j ]
932  // shift left, append
933  : [ for (j = v) j, for (j = [0 : s-1]) nv ];
934 
935 //! Insert a new value into an iterable value.
936 /***************************************************************************//**
937  \param nv <value> A new value to insert.
938  \param v <iterable> An iterable value.
939 
940  \param i <integer> The index insert position.
941 
942  \param mv <list | string | value> Match value candidates.
943  \param mi <integer> The matched selection index.
944 
945  \param s <boolean> Element matching search method.
946  \param si <integer> The search element index when matching.
947 
948  \returns (1) <list> The list with \p nv inserted into \p v at the
949  specified position.
950  (2) Returns \b undef when no value of \p mv exists in
951  \p v, when `(mi + 1)` exceeds the matched element
952  count, when \p i does not map to an element of \p v, or
953  when \p v is not defined or is not iterable.
954 
955  \details
956 
957  When `s == true`, [search]\‍() is used to match elements. When `s ==
958  false`, find() is used.
959 
960  The insert position can be specified by an index, an element match
961  value, or list of potential match values. When multiple matches
962  exists, \p mi indicates the insert position. When more than one
963  insert position criteria is specified, the order of precedence is:
964  (1) \p mv then (2) \p i. To insert a list of elements together as a
965  list to \p v, enclose the elements of \p nv with a second set of
966  brackets.
967 
968  \amu_eval (${group_references})
969 *******************************************************************************/
970 function insert
971 (
972  nv,
973  v,
974  i = 0,
975  mv,
976  mi = 0,
977  s = true,
978  si
979 ) = !is_iterable(v) ? undef
980  // when 'v' is empty and 'i' or 'mv' specified
981  : (is_empty(v) && ( (i != 0) || !is_undef(mv)) ) ? undef
982  // when 'v' is empty, simply return 'nv'
983  : is_empty(v) ? concat(nv)
984  : let
985  ( // identify specified insert position 'p' or return undef
986  p = is_defined(mv) ?
987  // search for 'mv' in 'v' selecting 'mi'
988  ( s == false ) ? find(mv, v, 0, si)[mi]
989  : merge_s(search(mv, v, 0, si), false)[mi]
990  // using 'i'; element position 'i' must exists in 'v' or is undef
991  : !is_between(i, 0, len(v)) ? undef
992  : i,
993  // generate result list head 'h'
994  h = ( !is_undef(p) && (p>0) ) ? [for (j = [0 : p-1]) v[j]] : empty_lst,
995  // generate result list tail 't'
996  t = ( is_undef(p) || (p>len(v)-1) ) ? empty_lst : [for (j = [p : len(v)-1]) v[j]]
997  )
998  // result valid iff a valid insert position was specified
999  is_undef(p) ? undef : concat(h, nv, t);
1000 
1001 //! Delete the first occurrence(s) of a matched value from an iterable value.
1002 /***************************************************************************//**
1003  \param v <iterable> The iterable value.
1004 
1005  \param mv <value> The match value.
1006 
1007  \param mc <integer> A match count.
1008  For `(mc >= 1)`, remove the first \p mc matches.
1009  For `(mc = 0)`, remove all matches.
1010 
1011  \returns (1) <list> The list with the first \p mc occurrences of the
1012  match value removed.
1013  (2) Returns \b undef when \p v is not defined, or is not
1014  iterable.
1015 *******************************************************************************/
1016 function delete_first
1017 (
1018  v,
1019  mv,
1020  mc = 1
1021 ) = !is_iterable(v) ? undef
1022  : let
1023  (
1024  p = find_all(mv, v),
1025  q = (mc == 0) ? p : firstn(p, mc)
1026  )
1027  [
1028  for (j = [0 : len(v)-1])
1029  if (is_empty(find_all(j, q)))
1030  v[j]
1031  ];
1032 
1033 //! Delete each match value from an iterable value.
1034 /***************************************************************************//**
1035  \param v <iterable> An iterable value.
1037  \param mv <iterable> The list of match values.
1038 
1039  \returns (1) <list> The list with all occurrence of the match
1040  value removed.
1041 *******************************************************************************/
1042 function delete_each
1043 (
1044  v,
1045  mv
1046 ) = is_empty(mv) ? v
1047  : delete_each( delete_first(v=v, mv=first(mv)), tailn(mv) );
1048 
1049 //! Delete elements from an iterable value.
1050 /***************************************************************************//**
1051  \param v <iterable> An iterable value.
1052 
1053  \param i <range | list | integer> Deletion Indexes.
1055  \param mv <list | string | value> Match value candidates.
1056  \param mc <integer> A match count.
1057  For `(mc >= 1)`, remove the first \p mc matches.
1058  For `(mc <= 0)`, remove all matches.
1059 
1060  \param s <boolean> Element matching search method.
1061  \param si <integer> The element column index when matching.
1062 
1063  \returns (1) <list> The list with all specified elements removed.
1064  (2) Returns \b undef when \p i does not map to an element
1065  of \p v, when \p v is not defined, or is not iterable.
1066 
1067 
1068  \details
1069 
1070  When `s == true`, [search]\‍() is used to match elements. When `s ==
1071  false`, find() is used.
1072 
1073  The elements to delete can be specified by an index position, a
1074  list of index positions, an index range, an element match value, or
1075  a list of element match values (when using [search]\‍()). When \p mv
1076  is a list of match values, all values of \p mv that exists in \p v
1077  are candidates for deletion. For each matching candidate, \p mc
1078  indicates the quantity to remove. When more than one deletion
1079  criteria is specified, the order of precedence is: (1) \p mv then
1080  (2) \p i.
1081 
1082  \amu_eval (${group_references})
1083 *******************************************************************************/
1084 function delete
1085 (
1086  v,
1087  i,
1088  mv,
1089  mc = 1,
1090  s = true,
1091  si
1092 ) = !is_iterable(v) ? undef
1093  // nothing to delete
1094  : is_empty(v) ? empty_lst
1095  // for 'i' a number, list or range; each indexed position must exists in 'v'
1096  : is_number(i) && !is_between(i, 0, len(v)-1) ? undef
1097  : is_list(i) && ((min([for (y=i) y])<0) || (max([for (y=i) y])>(len(v)-1))) ? undef
1098  : is_range(i) && ((min([for (y=i) y])<0) || (max([for (y=i) y])>(len(v)-1))) ? undef
1099  : let
1100  ( // identify specified deletion position(s) 'p' or return undef
1101  p = is_defined(mv) ?
1102  // search for 'mv' in 'v' selecting 'mi'
1103  ( s == false ) ? find(mv, v, mc, si)
1104  : merge_s(search(mv, v, mc, si), false)
1105  // using 'i'; for single number, format as list
1106  : is_number(i) ? [i]
1107  // using 'i'; pass list as specified
1108  : is_list(i) ? i
1109  // using 'i'; enumerate range to list
1110  : is_range(i) ? [for (y=i) y]
1111  : undef
1112  )
1113  [ // output only elements of 'v' that do not exists in 'p'
1114  for (j = [0 : len(v)-1])
1115  if (is_empty(find(j, p))) v[j]
1116  ];
1117 
1118 //! Replace the first occurrence(s) of a matched value in iterable value.
1119 /***************************************************************************//**
1120  \param v <iterable> The iterable value.
1121 
1122  \param mv <value> The match value.
1123  \param nv <value> The new value.
1124 
1125  \param mc <integer> A match count.
1126  For `(mc >= 1)`, replaces the first \p mc matches.
1127  For `(mc = 0)`, replaces all matches.
1128 
1129  \returns (1) <list> The list with the first \mc occurrences of the
1130  match value replaced by \p nv.
1131  (2) Returns \b undef when \p v is not defined, or is not
1132  iterable.
1133 *******************************************************************************/
1134 function replace_first
1135 (
1136  v,
1137  mv,
1138  nv,
1139  mc = 1
1140 ) = !is_iterable(v) ? undef
1141  : let
1142  (
1143  p = find_all(mv, v),
1144  q = (mc == 0) ? p : firstn(p, mc)
1145  )
1146  [
1147  for (j = [0 : len(v)-1])
1148  if (is_empty(find_all(j, q)))
1149  v[j]
1150  else
1151  nv
1152  ];
1153 
1154 //! Strip all matching values from an iterable value.
1155 /***************************************************************************//**
1156  \param v <iterable> An iterable value.
1157  \param mv <value> A match value.
1158 
1159  \returns (1) <list> The list 'v' with all elements equal \p mv removed.
1160  (2) Returns \b undef when \p v is not defined or is not iterable.
1161 *******************************************************************************/
1162 function strip
1163 (
1164  v,
1165  mv = empty_lst
1166 ) = !is_iterable(v) ? undef
1167  : [for (e = v) if (e != mv) e];
1168 
1169 //! Apply a binary mask to an interable value.
1170 /***************************************************************************//**
1171  \param v <iterable> An iterable value.
1172  \param m <iterable> A binary mask list (or string) of \p 0 or \p 1.
1173  \param r <boolean> Right align the mask to \p v value.
1174  \param o <integer> A positive or negative mask offset.
1175  \param u <value> The value assigned to elements of the mask that
1176  does not exists or are undefined in \p v.
1177  \param z <value> The value assigned to masked elements.
1178 
1179  \returns (1) <value> A list containing the masked values of \p v.
1180  (2) Returns \b v as a list when \p m is not defined.
1181  (3) Returns \p undef when \p m is not iterable or contains
1182  values other than zero or one.
1183 
1184  \details
1185 
1186  This mask may be specified as a list or string and is composed of
1187  ones and zeros. One indicates that an element value of \p v is
1188  passed and a zero indicates that a value of \p v is to be replaced
1189  with \p z.
1190 *******************************************************************************/
1191 function mask
1192 (
1193  v,
1194  m,
1195  r = false,
1196  o = 0,
1197  u = undef,
1198  z = 0
1199 ) = is_undef(m) ? headn(v, 0)
1200  // if defined, 'm' must be iterable
1201  : !is_iterable(m) ? undef
1202  // string mask may only include "01"
1203  : is_string(m) && !is_empty(delete(m, mv="01", mc=0)) ? undef
1204  // list mask may only include [0, 1]
1205  : is_list(m) && !is_empty(delete(m, mv=[0,1], mc=0)) ? undef
1206  : let
1207  ( // calculate the mask base offset
1208  l = is_iterable(v) ? len(v) : 0,
1209  j = ((r == true) ? l - len(m) : 0) + o
1210  )
1211  [
1212  for (i = [0 : len(m)-1])
1213  (m[i] == 1 || m[i] == "1") ? defined_e_or(v, i+j, u)
1214  : exists_e(i+j, v) ? z : u
1215  ];
1216 
1217 //! Return a list of the unique elements of an iterable value.
1218 /***************************************************************************//**
1219  \param v <iterable> An iterable value.
1220 
1221  \returns (1) <list> A list of unique elements with order preserved.
1222  (2) Returns \b undef when \p v is not defined or is not
1223  iterable.
1224 
1225  \warning Any and all list elements of \p v that have the value of \b
1226  undef are ignored and is not considered to be a unique.
1227 *******************************************************************************/
1228 function unique
1229 (
1230  v
1231 ) = is_undef(v) ? empty_lst
1232  : !is_iterable(v) ? [v]
1233  // handled empty list or empty string
1234  : (len(v) == 0) ? empty_lst
1235  // last element. filter case where first element of list is [undef]
1236  : (len(v) == 1) ? (v == [undef]) ? empty_lst : headn(v, 0)
1237  // set s=false to use find() for single element matching
1238  : exists(last(v), headn(v), s=false) ? unique(headn(v))
1239  : concat(unique(headn(v)), lastn(v));
1240 
1241 //! Return a list of the common elements of two iterable values.
1242 /***************************************************************************//**
1243  \param v1 <iterable> The first iterable value.
1244  \param v2 <iterable> The second iterable value.
1245 
1246  \param e <iterable> The common elements list (used for recursion
1247  value tracking or may be initialed by user).
1248 
1249  \returns (1) <list> The list of elements common to both iterable
1250  values as list intersection with a one-to-one
1251  correspondence among the elements.
1252  (2) Returns \b empty_lst when either \p v1 or \p v2 is
1253  empty.
1254 *******************************************************************************/
1255 function common
1256 (
1257  v1,
1258  v2,
1259  e = empty_lst
1260 ) = let( mv = first(v1) )
1261  is_empty(v1) ? e
1262  : (find_all(mv, v2) != empty_lst) ?
1263  common( tailn(v1), delete_first(v=v2, mv=mv), concat(e, [mv]) )
1264  : common( tailn(v1), delete_first(v=v2, mv=mv), e);
1265 
1266 //! Return a list of the elements not present in both iterable values.
1267 /***************************************************************************//**
1268  \param v1 <iterable> The first iterable value.
1269  \param v2 <iterable> The second iterable value.
1270 
1271  \returns (1) <list> The list of elements that do not exists in both
1272  iterable values as a list difference with a one-to-one
1273  correspondence among the elements.
1274  (2) Returns \b empty_lst when \p v1 and \p v2 are
1275  identical, or when both are empty.
1276 *******************************************************************************/
1277 function not_common
1278 (
1279  v1,
1280  v2
1281 ) = let
1282  (
1283  d1 = delete_each(v1, v2),
1284  d2 = delete_each(v2, v1)
1285  )
1286  concat(d1, d2);
1287 
1288 
1289 //! @}
1290 //! @}
1291 
1292 //----------------------------------------------------------------------------//
1293 // openscad-amu auxiliary scripts
1294 //----------------------------------------------------------------------------//
1295 
1296 /*
1297 BEGIN_SCOPE validate;
1298  BEGIN_OPENSCAD;
1299  include <omdl-base.scad>;
1300  include <common/validation.scad>;
1301 
1302  function fmt( id, td, v1, v2, v3 ) = table_validate_fmt(id, td, v1, v2, v3);
1303  function v1(db, id) = table_validate_get_v1(db, id);
1304  t = true; f = false; u = undef; s = validation_skip;
1306  tbl_test_values =
1307  [
1308  fmt("t01", "The undefined value", undef),
1309  fmt("t02", "The empty list", empty_lst),
1310  fmt("t03", "A long range", [0:0.5:9]),
1311  fmt("t04", "string = (A string)", "A string"),
1312  fmt("t05", "List-4 fruit", ["orange","apple","grape","banana"]),
1313  fmt("t06", "List-7 characters", ["b","a","n","a","n","a","s"]),
1314  fmt("t07", "List-1 undefined", [undef]),
1315  fmt("t08", "List-2 integers-2", [[1,2],[2,3]]),
1316  fmt("t09", "List-4 iterable-2", ["ab",[1,2],[2,3],[4,5]]),
1317  fmt("t10", "List-4 iterable-3", [[1,2,3],[4,5,6],[7,8,9],["a","b","c"]]),
1318  fmt("t11", "List-15 of integers", [for (i=[0:15]) i])
1319  ];
1320 
1321  tbl_test_answers =
1322  [
1323  ["defined_e_or_DE3",
1324  "default", // t01
1325  "default", // t02
1326  "default", // t03
1327  "t", // t04
1328  "banana", // t05
1329  "a", // t06
1330  "default", // t07
1331  "default", // t08
1332  [4,5], // t09
1333  ["a","b","c"], // t10
1334  3 // t11
1335  ],
1336  ["find_12",
1337  empty_lst, // t01
1338  empty_lst, // t02
1339  empty_lst, // t03
1340  empty_lst, // t04
1341  empty_lst, // t05
1342  empty_lst, // t06
1343  empty_lst, // t07
1344  [0], // t08
1345  [1], // t09
1346  empty_lst, // t10
1347  empty_lst // t11
1348  ],
1349  ["count_S1",
1350  0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1
1351  ],
1352  ["exists_S1",
1353  f, f, f, f, f, f, f, t, t, t, t
1354  ],
1355  ["exists_e_5",
1356  f, f, f, t, f, t, f, f, f, f, t
1357  ],
1358  ["first",
1359  undef, // t01
1360  undef, // t02
1361  0, // t03
1362  "A", // t04
1363  "orange", // t05
1364  "b", // t06
1365  undef, // t07
1366  [1,2], // t08
1367  "ab", // t09
1368  [1,2,3], // t10
1369  0 // t11
1370  ],
1371  ["second",
1372  undef, // t01
1373  undef, // t02
1374  0.5, // t03
1375  " ", // t04
1376  "apple", // t05
1377  "a", // t06
1378  undef, // t07
1379  [2,3], // t08
1380  [1,2], // t09
1381  [4,5,6], // t10
1382  1 // t11
1383  ],
1384  ["third",
1385  undef, // t01
1386  undef, // t02
1387  9, // t03
1388  "s", // t04
1389  "grape", // t05
1390  "n", // t06
1391  undef, // t07
1392  undef, // t08
1393  [2,3], // t09
1394  [7,8,9], // t10
1395  2 // t11
1396  ],
1397  ["last",
1398  undef, // t01
1399  undef, // t02
1400  undef, // t03
1401  "g", // t04
1402  "banana", // t05
1403  "s", // t06
1404  undef, // t07
1405  [2,3], // t08
1406  [4,5], // t09
1407  ["a","b","c"], // t10
1408  15 // t11
1409  ],
1410  ["middle",
1411  undef, // t01
1412  undef, // t02
1413  undef, // t03
1414  "r", // t04
1415  "grape", // t05
1416  "a", // t06
1417  undef, // t07
1418  [2,3], // t08
1419  [2,3], // t09
1420  [7,8,9], // t10
1421  8 // t11
1422  ],
1423  ["first2",
1424  undef, // t01
1425  undef, // t02
1426  undef, // t03
1427  ["A"," "], // t04
1428  ["orange","apple"], // t05
1429  ["b","a"], // t06
1430  undef, // t07
1431  [[1,2],[2,3]], // t08
1432  ["ab", [1,2]], // t09
1433  [[1,2,3],[4,5,6]], // t10
1434  [0,1] // t11
1435  ],
1436  ["first3",
1437  undef, // t01
1438  undef, // t02
1439  undef, // t03
1440  ["A"," ","s"], // t04
1441  ["orange","apple","grape"], // t05
1442  ["b","a","n"], // t06
1443  undef, // t07
1444  undef, // t08
1445  ["ab", [1,2],[2,3]], // t09
1446  [[1,2,3],[4,5,6],[7,8,9]], // t10
1447  [0,1,2] // t11
1448  ],
1449  ["last2",
1450  undef, // t01
1451  undef, // t02
1452  undef, // t03
1453  ["n","g"], // t04
1454  ["grape","banana"], // t05
1455  ["a","s"], // t06
1456  undef, // t07
1457  [[1,2],[2,3]], // t08
1458  [[2,3], [4,5]], // t09
1459  [[7,8,9],["a","b","c"]], // t10
1460  [14,15] // t11
1461  ],
1462  ["last3",
1463  undef, // t01
1464  undef, // t02
1465  undef, // t03
1466  ["i","n","g"], // t04
1467  ["apple","grape","banana"], // t05
1468  ["n","a","s"], // t06
1469  undef, // t07
1470  undef, // t08
1471  [[1,2],[2,3],[4,5]], // t09
1472  [[4,5,6],[7,8,9],["a","b","c"]], // t10
1473  [13,14,15] // t11
1474  ],
1475  ["firstn_1",
1476  undef, // t01
1477  undef, // t02
1478  undef, // t03
1479  ["A"], // t04
1480  ["orange"], // t05
1481  ["b"], // t06
1482  [undef], // t07
1483  [[1,2]], // t08
1484  ["ab"], // t09
1485  [[1,2,3]], // t10
1486  [0] // t11
1487  ],
1488  ["lastn_1",
1489  undef, // t01
1490  undef, // t02
1491  undef, // t03
1492  ["g"], // t04
1493  ["banana"], // t05
1494  ["s"], // t06
1495  [undef], // t07
1496  [[2,3]], // t08
1497  [[4,5]], // t09
1498  [["a","b","c"]], // t10
1499  [15] // t11
1500  ],
1501  ["headn_1",
1502  undef, // t01
1503  undef, // t02
1504  undef, // t03
1505  ["A"," ","s","t","r","i","n"], // t04
1506  ["orange","apple","grape"], // t05
1507  ["b","a","n","a","n","a"], // t06
1508  empty_lst, // t07
1509  [[1,2]], // t08
1510  ["ab",[1,2],[2,3]], // t09
1511  [[1,2,3],[4,5,6],[7,8,9]], // t10
1512  [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] // t11
1513  ],
1514  ["tailn_1",
1515  undef, // t01
1516  undef, // t02
1517  undef, // t03
1518  [" ","s","t","r","i","n","g"], // t04
1519  ["apple","grape","banana"], // t05
1520  ["a","n","a","n","a","s"], // t06
1521  empty_lst, // t07
1522  [[2,3]], // t08
1523  [[1,2],[2,3],[4,5]], // t09
1524  [[4,5,6],[7,8,9],["a","b","c"]], // t10
1525  [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] // t11
1526  ],
1527  ["reverse",
1528  undef, // t01
1529  empty_lst, // t02
1530  undef, // t03
1531  ["g","n","i","r","t","s"," ","A"], // t04
1532  ["banana","grape","apple","orange"], // t05
1533  ["s","a","n","a","n","a","b"], // t06
1534  [undef], // t07
1535  [[2,3],[1,2]], // t08
1536  [[4,5],[2,3],[1,2],"ab"], // t09
1537  [["a","b","c"],[7,8,9],[4,5,6],[1,2,3]], // t10
1538  [15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0] // t11
1539  ],
1540  ["shift_cd_r1",
1541  undef, // t01
1542  empty_lst, // t02
1543  undef, // t03
1544  ["g","A"," ","s","t","r","i","n"], // t04
1545  ["banana","orange","apple","grape"], // t05
1546  ["s","b","a","n","a","n","a"], // t06
1547  [undef], // t07
1548  [[2,3],[1,2]], // t08
1549  [[4,5],"ab",[1,2],[2,3]], // t09
1550  [["a","b","c"],[1,2,3],[4,5,6],[7,8,9]], // t10
1551  [15,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] // t11
1552  ],
1553  ["shift_cd_l1",
1554  undef, // t01
1555  empty_lst, // t02
1556  undef, // t03
1557  [" ","s","t","r","i","n","g","A"], // t04
1558  ["apple","grape","banana","orange"], // t05
1559  ["a","n","a","n","a","s","b"], // t06
1560  [undef], // t07
1561  [[2,3],[1,2]], // t08
1562  [[1,2],[2,3],[4,5],"ab"], // t09
1563  [[4,5,6],[7,8,9],["a","b","c"],[1,2,3]], // t10
1564  [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0] // t11
1565  ],
1566  ["select_r_02",
1567  undef, // t01
1568  empty_lst, // t02
1569  undef, // t03
1570  ["A"," ","s"], // t04
1571  ["orange","apple","grape"], // t05
1572  ["b","a","n"], // t06
1573  undef, // t07
1574  undef, // t08
1575  ["ab",[1,2],[2,3]], // t09
1576  [[1,2,3],[4,5,6],[7,8,9]], // t10
1577  [0,1,2] // t11
1578  ],
1579  ["sequence_ns_31",
1580  empty_lst, // t01
1581  empty_lst, // t02
1582  empty_lst, // t03
1583  [
1584  ["A"," ","s"],[" ","s","t"],["s","t","r"],
1585  ["t","r","i"],["r","i","n"],["i","n","g"]
1586  ], // t04
1587  [
1588  ["orange","apple","grape"],
1589  ["apple","grape","banana"]
1590  ], // t05
1591  [
1592  ["b","a","n"],["a","n","a"],["n","a","n"],
1593  ["a","n","a"],["n","a","s"]
1594  ], // t06
1595  empty_lst, // t07
1596  empty_lst, // t08
1597  [["ab",[1,2],[2,3]],[[1,2],[2,3],[4,5]]], // t09
1598  [
1599  [[1,2,3],[4,5,6],[7,8,9]],
1600  [[4,5,6],[7,8,9],["a","b","c"]]
1601  ], // t10
1602  [
1603  [0,1,2],[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7],
1604  [6,7,8],[7,8,9],[8,9,10],[9,10,11],[10,11,12],
1605  [11,12,13],[12,13,14],[13,14,15]
1606  ] // t11
1607  ],
1608  ["append_e_T0",
1609  undef, // t01
1610  [[0]], // t02
1611  undef, // t03
1612  [
1613  ["A",0],[" ",0],["s",0],["t",0],
1614  ["r",0],["i",0],["n",0],["g",0]
1615  ], // t04
1616  [
1617  ["orange",0],["apple",0],
1618  ["grape",0],["banana",0]
1619  ], // t05
1620  [
1621  ["b",0],["a",0],["n",0],["a",0],
1622  ["n",0],["a",0],["s",0]
1623  ], // t06
1624  [[undef,0]], // t07
1625  [[1,2,0],[2,3,0]], // t08
1626  [["ab",0],[1,2,0],[2,3,0],[4,5,0]], // t09
1627  [[1,2,3,0],[4,5,6,0],[7,8,9,0],["a","b","c",0]], // t10
1628  [
1629  [0,0],[1,0],[2,0],[3,0],[4,0],[5,0],
1630  [6,0],[7,0],[8,0],[9,0],[10,0],[11,0],
1631  [12,0],[13,0],[14,0],[15,0]
1632  ] // t11
1633  ],
1634  ["insert_T0",
1635  undef, // t01
1636  undef, // t02
1637  undef, // t03
1638  undef, // t04
1639  ["orange",0,"apple","grape","banana"], // t05
1640  ["b","a","n","a","n","a",0,"s"], // t06
1641  undef, // t07
1642  [[1,2],0,[2,3]], // t08
1643  ["ab",[1,2],0,[2,3],[4,5]], // t09
1644  undef, // t10
1645  [0,1,2,3,4,0,5,6,7,8,9,10,11,12,13,14,15] // t11
1646  ],
1647  ["delete_T0",
1648  undef, // t01
1649  empty_lst, // t02
1650  undef, // t03
1651  ["A"," ","s","t","r","i","n","g"], // t04
1652  ["orange","grape","banana"], // t05
1653  ["b","a","n","a","n","a"], // t06
1654  [undef], // t07
1655  [[1,2]], // t08
1656  ["ab",[1,2],[4,5]], // t09
1657  [[1,2,3],[4,5,6],[7,8,9],["a","b","c"]], // t10
1658  [0,1,2,3,4,6,7,8,9,10,11,12,13,14,15] // t11
1659  ],
1660  ["strip",
1661  undef, // t01
1662  empty_lst, // t02
1663  undef, // t03
1664  ["A"," ","s","t","r","i","n","g"], // t04
1665  ["orange","apple","grape","banana"], // t05
1666  ["b","a","n","a","n","a","s"], // t06
1667  [undef], // t07
1668  [[1,2],[2,3]], // t08
1669  ["ab",[1,2],[2,3],[4,5]], // t09
1670  [[1,2,3],[4,5,6],[7,8,9],["a","b","c"]], // t10
1671  [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] // t11
1672  ],
1673  ["mask_01R",
1674  [undef,undef], // t01
1675  [undef,undef], // t02
1676  [undef,undef], // t03
1677  [0,"g"], // t04
1678  [0,"banana"], // t05
1679  [0,"s"], // t06
1680  [undef,undef], // t07
1681  [0,[2,3]], // t08
1682  [0,[4,5]], // t09
1683  [0,["a","b","c"]], // t10
1684  [0,15] // t11
1685  ],
1686  ["unique",
1687  empty_lst, // t01
1688  empty_lst, // t02
1689  [[0:0.5:9]], // t03
1690  ["A"," ","s","t","r","i","n","g"], // t04
1691  ["orange","apple","grape","banana"], // t05
1692  ["b","a","n","s"], // t06
1693  empty_lst, // t07
1694  [[1,2],[2,3]], // t08
1695  ["ab",[1,2],[2,3],[4,5]], // t09
1696  [[1,2,3],[4,5,6],[7,8,9],["a","b","c"]], // t10
1697  [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] // t11
1698  ]
1699  ];
1700 
1701  db = table_validate_init( tbl_test_values, tbl_test_answers );
1702 
1703  table_validate_start( db );
1704  test_ids = table_validate_get_ids( db );
1705 
1706  for (id=test_ids) table_validate( db, id, "defined_e_or_DE3", 1, defined_e_or( v1(db,id), 3, "default" ) );
1707  for (id=test_ids) table_validate( db, id, "defined_e_or_DE3", 1, defined_eon_or( v1(db,id), 3, "default" ) );
1708  // defined_eonb_or()
1709  // defined_fle_or()
1710  // defined_ei_or()
1711  // find_all()
1712  for (id=test_ids) table_validate( db, id, "find_12", 1, find( [1,2], v1(db,id) ) );
1713  for (id=test_ids) table_validate( db, id, "count_S1", 1, count( 1, v1(db,id), true ) );
1714  for (id=test_ids) table_validate( db, id, "exists_S1", 1, exists( 1, v1(db,id), true ) );
1715  for (id=test_ids) table_validate( db, id, "exists_e_5", 1, exists_e( 5, v1(db,id )) );
1716  for (id=test_ids) table_validate( db, id, "first", 1, first( v1(db,id) ) );
1717  for (id=test_ids) table_validate( db, id, "second", 1, second( v1(db,id) ) );
1718  for (id=test_ids) table_validate( db, id, "third", 1, third( v1(db,id) ) );
1719  for (id=test_ids) table_validate( db, id, "last", 1, last( v1(db,id) ) );
1720  for (id=test_ids) table_validate( db, id, "middle", 1, middle( v1(db,id) ) );
1721  for (id=test_ids) table_validate( db, id, "first2", 1, first2( v1(db,id) ) );
1722  for (id=test_ids) table_validate( db, id, "first3", 1, first3( v1(db,id) ) );
1723  for (id=test_ids) table_validate( db, id, "last2", 1, last2( v1(db,id) ) );
1724  for (id=test_ids) table_validate( db, id, "last3", 1, last3( v1(db,id) ) );
1725  for (id=test_ids) table_validate( db, id, "firstn_1", 1, firstn( v1(db,id), n=1 ) );
1726  for (id=test_ids) table_validate( db, id, "lastn_1", 1, lastn( v1(db,id), n=1 ) );
1727  for (id=test_ids) table_validate( db, id, "headn_1", 1, headn( v1(db,id), n=1 ) );
1728  for (id=test_ids) table_validate( db, id, "tailn_1", 1, tailn( v1(db,id), n=1 ) );
1729  for (id=test_ids) table_validate( db, id, "reverse", 1, reverse( v1(db,id) ) );
1730  for (id=test_ids) table_validate( db, id, "shift_cd_r1", 1, shift_cd( v1(db,id), n=1, r=true ) );
1731  for (id=test_ids) table_validate( db, id, "shift_cd_l1", 1, shift_cd( v1(db,id), n=1, r=false ) );
1732  // shift_ci()
1733  for (id=test_ids) table_validate( db, id, "select_r_02", 1, select_r( v1(db,id), i=[0:2] ) );
1734  for (id=test_ids) table_validate( db, id, "sequence_ns_31", 1, sequence_ns( v1(db,id), n=3, s=1 ) );
1735  // combine_ns()
1736  // permute_ns()
1737  // permute_ns_r()
1738  for (id=test_ids) table_validate( db, id, "append_e_T0", 1, append_e( 0, v1(db,id) ) );
1739  // append_v()
1740  for (id=test_ids) table_validate( db, id, "insert_T0", 1, insert( 0, v1(db,id), mv=["x","r","apple","s",[2,3],5] ) );
1741  // delete_first()
1742  // delete_each()
1743  for (id=test_ids) table_validate( db, id, "delete_T0", 1, delete( v1(db,id), mv=["x","r","apple","s",[2,3],5] ) );
1744  // replace_first()
1745  for (id=test_ids) table_validate( db, id, "strip", 1, strip( v1(db,id) ) );
1746  for (id=test_ids) table_validate( db, id, "mask_01R", 1, mask( v1(db,id), [0,1], r=true ) );
1747  for (id=test_ids) table_validate( db, id, "unique", 1, unique( v1(db,id) ) );
1748  // common()
1749  // not_common()
1750 
1751  // end_include
1752  END_OPENSCAD;
1753 
1754  BEGIN_MFSCRIPT;
1755  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
1756  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
1757  END_MFSCRIPT;
1758 END_SCOPE;
1759 */
1760 
1761 //----------------------------------------------------------------------------//
1762 // end of file
1763 //----------------------------------------------------------------------------//
empty_lst
<list> A list with no values (the empty list).
Definition: constants.scad:304
function headn(v, n=1)
Return a list containing all but the last n elements of an iterable value.
function firstn(v, n=1)
Return a list containing the first n elements of an iterable value.
function unique(v)
Return a list of the unique elements of an iterable value.
function select_r(v, i)
Select a range of elements from an iterable value.
function append_e(nv, v, r=true, j=true, l=true)
Append a value to each element of an iterable value.
function find(mv, v, c=1, i, i1=0, i2)
Find the occurrences of a match value in an iterable value.
function defined_ei_or(v, i, d, n)
Returns an element from an iterable if it exists and is a iterable, otherwise returns a default value...
function first3(v)
Return a list containing the first three elements of an iterable value.
function defined_eonb_or(v, i, d)
Returns the list element or scalar numeric or boolean value if defined, otherwise returns the default...
function first2(v)
Return a list containing the first two elements of an iterable value.
function defined_e_or(v, i, d)
Returns an element from an iterable if it exists, or a default value if not.
function last3(v)
Return a list containing the last three elements of an iterable value.
function delete_first(v, mv, mc=1)
Delete the first occurrence(s) of a matched value from an iterable value.
function third(v)
Return the third element of an iterable value.
function last(v)
Return the last element of an iterable value.
function exists(mv, v, s=true, i)
Check for the existence of a match value in an iterable value.
function count(mv, v, s=true, i)
Count all occurrences of a match value in an iterable value.
function not_common(v1, v2)
Return a list of the elements not present in both iterable values.
function insert(nv, v, i=0, mv, mi=0, s=true, si)
Insert a new value into an iterable value.
function exists_e(i, v)
Test if an element exists at a specified index of an iterable value.
function find_all(mv, v)
Find all occurrences of a match value in an iterable value.
function mask(v, m, r=false, o=0, u=undef, z=0)
Apply a binary mask to an interable value.
function defined_fle_or(v, i, d)
Return the first defined specified element in a list of lists, otherwise returns the given default va...
function combine_ns(v, n)
Return all n-sized set combinations of iterable value.
function strip(v, mv=empty_lst)
Strip all matching values from an iterable value.
function second(v)
Return the second element of an iterable value.
function permute_ns(v, n)
Return all ordered n-sized set permutations of iterable value.
function defined_eon_or(v, i, d)
Returns the list element or scalar numeric value if defined, otherwise returns the default value.
function lastn(v, n=1)
Return a list containing the last n elements of an iterable value.
function middle(v)
Return the middle element of an iterable value.
function delete(v, i, mv, mc=1, s=true, si)
Delete elements from an iterable value.
function replace_first(v, mv, nv, mc=1)
Replace the first occurrence(s) of a matched value in iterable value.
function first(v)
Return the first element of an iterable value.
function append_v(nv, v, n=0, r=false)
Append a value to the end or beginning of an iterable value.
function delete_each(v, mv)
Delete each match value from an iterable value.
function permute_ns_r(v, n)
Return all ordered n-size set permutations of iterable value with repetition allowed.
function sequence_ns(v, n=1, s=1, w=false)
Return a list of all n-element sequential-subsets of an iterable value.
function shift_ci(v, n=0, r=true, i)
Shift-in a value to the elements of a given iterable value.
function shift_cd(v, n=0, r=true, d=false)
Circularly shift the elements of an iterable, with an optional element drop.
function common(v1, v2, e=empty_lst)
Return a list of the common elements of two iterable values.
function last2(v)
Return a list containing the last two elements of an iterable value.
function tailn(v, n=1)
Return a list containing all but the first n elements of an iterable value.
function reverse(v)
Reverse the elements of an iterable value.
function all_defined(v)
Test if no element of an iterable value has an undefined value.
function is_iterable(v)
Test if a value has multiple parts and is iterable.
function is_empty(v)
Test if an iterable value is empty.
function consts(l, v, u=false)
Create a list of constant or incrementing elements.
function merge_s(v, r=false)
Serially merge the elements of a list.
function is_between(v, l, u)
Test if a numerical value is between an upper and lower bounds.
function is_defined(v)
Test if a value is defined.
function is_number(v)
Test if a value is a number.
function is_range(v)
Test if a value is a range definition.