From c98a3dfe9a7f379f5908de18ee7d9de82094a395 Mon Sep 17 00:00:00 2001 From: Garth Minette Date: Wed, 30 Jun 2021 17:05:44 -0700 Subject: [PATCH] Add all_integer() and group_data(). --- arrays.scad | 33 +++++++++++++++++++++++++++++++++ common.scad | 1 + math.scad | 25 +++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/arrays.scad b/arrays.scad index 3e67724..bf236ce 100644 --- a/arrays.scad +++ b/arrays.scad @@ -1796,6 +1796,39 @@ function array_group(v, cnt=2, dflt=0) = [for (i = [0:cnt:len(v)-1]) [for (j = [0:1:cnt-1]) default(v[i+j], dflt)]]; +// Function: group_data() +// Usage: +// groupings = group_data(groups, values); +// Topics: Array Handling +// See Also: zip(), zip_long(), array_group() +// Description: +// Given a list of integer group numbers, and an equal-length list of values, +// returns a list of groups with the values sorted into the corresponding groups. +// Ie: if you have a groups index list of [2,3,2] and values of ["A","B","C"], then +// the values "A" and "C" will be put in group 2, and "B" will be in group 3. +// Groups that have no values grouped into them will be an empty list. So the +// above would return [[], [], ["A","C"], ["B"]] +// Arguments: +// groups = A list of integer group index numbers. +// values = A list of values to sort into groups. +// Example: +// groups = group_data([1,2,0], ["A","B","C"]); // Returns [["B"],["C"],["A"]] +// Example: +// groups = group_data([1,3,1], ["A","B","C"]); // Returns [[],["A","C"],[],["B"]] +function group_data(groups, values) = + assert(all_integer(groups) && all_nonnegative(groups)); + assert(is_list(values)); + assert(len(groups)==len(values), + "The groups and values arguments should be lists of matching length.") + let( sorted = _group_sort_by_index(zip(groups,values),0) ) + // retrieve values and insert [] + [for(i=idx(sorted)) + let( a = i==0? 0 : sorted[i-1][0][0]+1, + g0 = sorted[i] ) + each [ for(j=[a:1:g0[0][0]-1]) [], [for(g1=g0) g1[1]] ] + ]; + + // Function: flatten() // Usage: // list = flatten(l); diff --git a/common.scad b/common.scad index 62c83ad..9ffade5 100644 --- a/common.scad +++ b/common.scad @@ -578,6 +578,7 @@ module no_module() { function _valstr(x) = is_list(x)? str("[",str_join([for (xx=x) _valstr(xx)],","),"]") : + is_num(x) && x==floor(x)? fmt_int(x) : is_finite(x)? fmt_float(x,12) : x; diff --git a/math.scad b/math.scad index 764cdc5..319f449 100644 --- a/math.scad +++ b/math.scad @@ -1204,6 +1204,31 @@ function all_equal(vec,eps=0) = eps==0 ? [for(v=vec) if (v!=vec[0]) v] == [] : [for(v=vec) if (!approx(v,vec[0])) v] == []; + +// Function: all_integer() +// Usage: +// bool = all_integer(x); +// Description: +// If given a number, returns true if the number is a finite integer. +// If given an empty list, returns false. If given a non-empty list, returns +// true if every item of the list is an integer. Otherwise, returns false. +// Arguments: +// x = The value to check. +// Examples: +// b = all_integer(true); // Returns: false +// b = all_integer("foo"); // Returns: false +// b = all_integer(4); // Returns: true +// b = all_integer(4.5); // Returns: false +// b = all_integer([]); // Returns: false +// b = all_integer([3,4,5]); // Returns: true +// b = all_integer([3,4.2,5]); // Returns: false +// b = all_integer([3,[4,7],5]); // Returns: false +function all_integer(x) = + is_num(x)? is_int(x) : + is_list(x)? (x != [] && [for (xx=x) if(!is_int(xx)) 1] == []) : + false; + + // Function: approx() // Usage: // b = approx(a,b,[eps])