Reorganize arrays.scad docs

This commit is contained in:
Revar Desmera 2020-01-09 16:10:18 -08:00
parent 231bb69634
commit 2f1760a342
2 changed files with 232 additions and 217 deletions

View file

@ -5,71 +5,16 @@
// ```
// use <BOSL2/std.scad>
// ```
//////////////////////////////////////////////////////////////////////
// Section: Terminology
//
// # Terminology
// - **List**: An ordered collection of zero or more items. ie: ["a", "b", "c"]
// - **Vector**: A list of numbers. ie: [4, 5, 6]
// - **Array**: A nested list of lists, or list of lists of lists, or deeper. ie: [[2,3], [4,5], [6,7]]
// - **Dimension**: The depth of nesting of lists in an array. A List is 1D. A list of lists is 2D. etc.
//////////////////////////////////////////////////////////////////////
// Section: List Operations
// Function: replist()
// Usage:
// replist(val, n)
// Description:
// Generates a list or array of `n` copies of the given `list`.
// If the count `n` is given as a list of counts, then this creates a
// multi-dimensional array, filled with `val`.
// Arguments:
// val = The value to repeat to make the list or array.
// n = The number of copies to make of `val`.
// Example:
// replist(1, 4); // Returns [1,1,1,1]
// replist(8, [2,3]); // Returns [[8,8,8], [8,8,8]]
// replist(0, [2,2,3]); // Returns [[[0,0,0],[0,0,0]], [[0,0,0],[0,0,0]]]
// replist([1,2,3],3); // Returns [[1,2,3], [1,2,3], [1,2,3]]
function replist(val, n, i=0) =
is_num(n)? [for(j=[1:1:n]) val] :
(i>=len(n))? val :
[for (j=[1:1:n[i]]) replist(val, n, i+1)];
// Function: in_list()
// Description: Returns true if value `x` is in list `l`.
// Arguments:
// x = The value to search for.
// l = The list to search.
// idx = If given, searches the given subindexes for matches for `x`.
// Example:
// in_list("bar", ["foo", "bar", "baz"]); // Returns true.
// in_list("bee", ["foo", "bar", "baz"]); // Returns false.
// in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1); // Returns true.
function in_list(x,l,idx=undef) = search([x], l, num_returns_per_match=1, index_col_num=idx) != [[]];
// Function: slice()
// Description:
// Returns a slice of a list. The first item is index 0.
// Negative indexes are counted back from the end. The last item is -1.
// Arguments:
// arr = The array/list to get the slice of.
// st = The index of the first item to return.
// end = The index after the last item to return, unless negative, in which case the last item to return.
// Example:
// slice([3,4,5,6,7,8,9], 3, 5); // Returns [6,7]
// slice([3,4,5,6,7,8,9], 2, -1); // Returns [5,6,7,8,9]
// slice([3,4,5,6,7,8,9], 1, 1); // Returns []
// slice([3,4,5,6,7,8,9], 6, -1); // Returns [9]
// slice([3,4,5,6,7,8,9], 2, -2); // Returns [5,6,7,8]
function slice(arr,st,end) = let(
s=st<0?(len(arr)+st):st,
e=end<0?(len(arr)+end+1):end
) [for (i=[s:1:e-1]) if (e>s) arr[i]];
// Section: List Query Operations
// Function: select()
@ -110,6 +55,124 @@ function select(list, start, end=undef) =
);
// Function: slice()
// Description:
// Returns a slice of a list. The first item is index 0.
// Negative indexes are counted back from the end. The last item is -1.
// Arguments:
// arr = The array/list to get the slice of.
// st = The index of the first item to return.
// end = The index after the last item to return, unless negative, in which case the last item to return.
// Example:
// slice([3,4,5,6,7,8,9], 3, 5); // Returns [6,7]
// slice([3,4,5,6,7,8,9], 2, -1); // Returns [5,6,7,8,9]
// slice([3,4,5,6,7,8,9], 1, 1); // Returns []
// slice([3,4,5,6,7,8,9], 6, -1); // Returns [9]
// slice([3,4,5,6,7,8,9], 2, -2); // Returns [5,6,7,8]
function slice(arr,st,end) = let(
s=st<0?(len(arr)+st):st,
e=end<0?(len(arr)+end+1):end
) [for (i=[s:1:e-1]) if (e>s) arr[i]];
// Function: in_list()
// Description: Returns true if value `x` is in list `l`.
// Arguments:
// x = The value to search for.
// l = The list to search.
// idx = If given, searches the given subindexes for matches for `x`.
// Example:
// in_list("bar", ["foo", "bar", "baz"]); // Returns true.
// in_list("bee", ["foo", "bar", "baz"]); // Returns false.
// in_list("bar", [[2,"foo"], [4,"bar"], [3,"baz"]], idx=1); // Returns true.
function in_list(x,l,idx=undef) = search([x], l, num_returns_per_match=1, index_col_num=idx) != [[]];
// Function: min_index()
// Usage:
// min_index(vals,[all]);
// Description:
// Returns the index of the first occurrence of the minimum value in the given list.
// If `all` is true then returns a list of all indices where the minimum value occurs.
// Arguments:
// vals = vector of values
// all = set to true to return indices of all occurences of the minimum. Default: false
// Example:
// min_index([5,3,9,6,2,7,8,2,1]); // Returns: 4
// min_index([5,3,9,6,2,7,8,2,1],all=true); // Returns: [4,7]
function min_index(vals, all=false) =
all ? search(min(vals),vals,0) : search(min(vals), vals)[0];
// Function: max_index()
// Usage:
// max_index(vals,[all]);
// Description:
// Returns the index of the first occurrence of the maximum value in the given list.
// If `all` is true then returns a list of all indices where the maximum value occurs.
// Arguments:
// vals = vector of values
// all = set to true to return indices of all occurences of the maximum. Default: false
// Example:
// max_index([5,3,9,6,2,7,8,9,1]); // Returns: 2
// max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7]
function max_index(vals, all=false) =
all ? search(max(vals),vals,0) : search(max(vals), vals)[0];
// Function: list_increasing()
// Usage:
// list_increasing(list)
// Description:
// Returns true if the list is (non-strictly) increasing
// Example:
// list_increasing([1,2,3,4]); // Returns: true
// list_increasing([1,3,2,4]); // Returns: false
// list_increasing([4,3,2,1]); // Returns: false
function list_increasing(list) =
assert(is_list(list)||is_string(list))
len([for (p=pair(list)) if(p.x>p.y) true])==0;
// Function: list_decreasing()
// Usage:
// list_decreasing(list)
// Description:
// Returns true if the list is (non-strictly) decreasing
// Example:
// list_decreasing([1,2,3,4]); // Returns: false
// list_decreasing([4,2,3,1]); // Returns: false
// list_decreasing([4,3,2,1]); // Returns: true
function list_decreasing(list) =
assert(is_list(list)||is_string(list))
len([for (p=pair(list)) if(p.x<p.y) true])==0;
// Section: Basic List Generation
// Function: replist()
// Usage:
// replist(val, n)
// Description:
// Generates a list or array of `n` copies of the given `list`.
// If the count `n` is given as a list of counts, then this creates a
// multi-dimensional array, filled with `val`.
// Arguments:
// val = The value to repeat to make the list or array.
// n = The number of copies to make of `val`.
// Example:
// replist(1, 4); // Returns [1,1,1,1]
// replist(8, [2,3]); // Returns [[8,8,8], [8,8,8]]
// replist(0, [2,2,3]); // Returns [[[0,0,0],[0,0,0]], [[0,0,0],[0,0,0]]]
// replist([1,2,3],3); // Returns [[1,2,3], [1,2,3], [1,2,3]]
function replist(val, n, i=0) =
is_num(n)? [for(j=[1:1:n]) val] :
(i>=len(n))? val :
[for (j=[1:1:n[i]]) replist(val, n, i+1)];
// Function: list_range()
// Usage:
// list_range(n, [s], [e])
@ -147,6 +210,10 @@ function list_range(n=undef, s=0, e=undef, step=undef) =
assert(e!=undef||n!=undef, "Must supply one of `n` or `e`.");
// Section: List Manipulation
// Function: reverse()
// Description: Reverses a list/array.
// Arguments:
@ -220,7 +287,7 @@ function deduplicate(list, closed=false, eps=EPSILON) =
// that the final length is exactly as requested. If you set it to `false` then the
// algorithm will favor uniformity and the output list may have a different number of
// entries due to rounding.
//
//
// When applied to a path the output path is the same geometrical shape but has some vertices
// repeated. This can be useful when you need to align paths with a different number of points.
// (See also subdivide_path for a different way to do that.)
@ -234,18 +301,17 @@ function deduplicate(list, closed=false, eps=EPSILON) =
// echo(repeat_entries(list, 6, exact=false)); // Ouputs [0,0,1,1,2,2,3,3]
// echo(repeat_entries(list, [1,1,2,1], exact=false)); // Ouputs [0,1,2,2,3]
function repeat_entries(list, N, exact = true) =
assert(is_list(list))
assert((is_num(N) && N>0) || is_vector(N),"Parameter N to repeat_entries must be postive number or vector")
let(
length = len(list),
reps_guess = is_list(N) ?
assert(len(N)==len(list), "Vector parameter N to repeat_entries has the wrong length")
N
: replist(N/length,length),
reps = exact ? _sum_preserving_round(reps_guess)
: [for (val=reps_guess) round(val)]
)
[for(i=[0:length-1]) each replist(list[i],reps[i])];
assert(is_list(list))
assert((is_num(N) && N>0) || is_vector(N),"Parameter N to repeat_entries must be postive number or vector")
let(
length = len(list),
reps_guess = is_list(N)?
assert(len(N)==len(list), "Vector parameter N to repeat_entries has the wrong length")
N : replist(N/length,length),
reps = exact? _sum_preserving_round(reps_guess) :
[for (val=reps_guess) round(val)]
)
[for(i=[0:length-1]) each replist(list[i],reps[i])];
// Function: list_set()
@ -294,6 +360,42 @@ function list_set(list=[],indices,values,dflt=0,minlen=0) =
);
// Function: list_insert()
// Usage:
// list_insert(list, pos, elements);
// Description:
// Insert `elements` into `list` before position `pos`.
// Example:
// list_insert([3,6,9,12],1,5); // Returns [3,5,6,9,12]
// list_insert([3,6,9,12],[1,3],[5,11]); // Returns [3,5,6,9,11,12]
function list_insert(list, pos, elements, _i=0) =
assert(is_list(list)||is_string(list))
is_list(pos)? (
assert(len(pos)==len(elements))
let(
idxs = sortidx(pos),
lastidx = pos[idxs[len(idxs)-1]]
)
concat(
[
for(i=idx(idxs)) each concat(
assert(pos[idxs[i]]<=len(list), "Indices in pos must be <= len(list)")
[for (j=[(i==0?0:pos[idxs[i-1]]):1:pos[idxs[i]]-1]) list[j]],
[elements[idxs[i]]]
)
],
[for (j=[lastidx:1:len(list)-1]) list[j]]
)
) : (
assert(pos<=len(list), "Indices in pos must be <= len(list)")
concat(
slice(list,0,pos),
elements,
(pos<len(list)? slice(list,pos,-1) : [])
)
);
// Function: list_remove()
// Usage:
// list_remove(list, elements)
@ -346,42 +448,6 @@ function list_remove_values(list,values=[],all=false) =
) list_remove(list,uidxs);
// Function: list_insert()
// Usage:
// list_insert(list, pos, elements);
// Description:
// Insert `elements` into `list` before position `pos`.
// Example:
// list_insert([3,6,9,12],1,5); // Returns [3,5,6,9,12]
// list_insert([3,6,9,12],[1,3],[5,11]); // Returns [3,5,6,9,11,12]
function list_insert(list, pos, elements, _i=0) =
assert(is_list(list)||is_string(list))
is_list(pos)? (
assert(len(pos)==len(elements))
let(
idxs = sortidx(pos),
lastidx = pos[idxs[len(idxs)-1]]
)
concat(
[
for(i=idx(idxs)) each concat(
assert(pos[idxs[i]]<=len(list), "Indices in pos must be <= len(list)")
[for (j=[(i==0?0:pos[idxs[i-1]]):1:pos[idxs[i]]-1]) list[j]],
[elements[idxs[i]]]
)
],
[for (j=[lastidx:1:len(list)-1]) list[j]]
)
) : (
assert(pos<=len(list), "Indices in pos must be <= len(list)")
concat(
slice(list,0,pos),
elements,
(pos<len(list)? slice(list,pos,-1) : [])
)
);
// Function: bselect()
// Usage:
// bselect(array,index);
@ -424,33 +490,8 @@ function list_bset(indexset, valuelist, dflt=0) =
);
// Function: list_increasing()
// Usage:
// list_increasing(list)
// Description:
// Returns true if the list is (non-strictly) increasing
// Example:
// list_increasing([1,2,3,4]); // Returns: true
// list_increasing([1,3,2,4]); // Returns: false
// list_increasing([4,3,2,1]); // Returns: false
function list_increasing(list) =
assert(is_list(list)||is_string(list))
len([for (p=pair(list)) if(p.x>p.y) true])==0;
// Function: list_decreasing()
// Usage:
// list_decreasing(list)
// Description:
// Returns true if the list is (non-strictly) decreasing
// Example:
// list_decreasing([1,2,3,4]); // Returns: false
// list_decreasing([4,2,3,1]); // Returns: false
// list_decreasing([4,3,2,1]); // Returns: true
function list_decreasing(list) =
assert(is_list(list)||is_string(list))
len([for (p=pair(list)) if(p.x<p.y) true])==0;
// Section: List Length Manipulation
// Function: list_shortest()
// Description:
@ -508,45 +549,8 @@ function list_fit(v, length, fill) =
let(l=len(v)) (l==length)? v : (l>length)? list_trim(v,length) : list_pad(v,length,fill);
// Function: idx()
// Usage:
// i = idx(list);
// for(i=idx(list)) ...
// Description:
// Returns the range of indexes for the given list.
// Arguments:
// list = The list to returns the index range of.
// step = The step size to stride through the list. Default: 1
// end = The delta from the end of the list. Default: -1
// start = The starting index. Default: 0
// Example(2D):
// colors = ["red", "green", "blue"];
// for (i=idx(colors)) right(20*i) color(colors[i]) circle(d=10);
function idx(list, step=1, end=-1,start=0) =
assert(is_list(list)||is_string(list))
[start : step : len(list)+end];
// Function: enumerate()
// Description:
// Returns a list, with each item of the given list `l` numbered in a sublist.
// Something like: `[[0,l[0]], [1,l[1]], [2,l[2]], ...]`
// Arguments:
// l = List to enumerate.
// idx = If given, enumerates just the given subindex items of `l`.
// Example:
// enumerate(["a","b","c"]); // Returns: [[0,"a"], [1,"b"], [2,"c"]]
// enumerate([[88,"a"],[76,"b"],[21,"c"]], idx=1); // Returns: [[0,"a"], [1,"b"], [2,"c"]]
// enumerate([["cat","a",12],["dog","b",10],["log","c",14]], idx=[1:2]); // Returns: [[0,"a",12], [1,"b",10], [2,"c",14]]
// Example(2D):
// colors = ["red", "green", "blue"];
// for (p=enumerate(colors)) right(20*p[0]) color(p[1]) circle(d=10);
function enumerate(l,idx=undef) =
assert(is_list(l)||is_string(list))
(idx==undef)?
[for (i=[0:1:len(l)-1]) [i,l[i]]] :
[for (i=[0:1:len(l)-1]) concat([i], [for (j=idx) l[i][j]])];
// Section: List Shuffling and Sorting
// Function: shuffle()
// Description:
@ -784,58 +788,46 @@ function unique(arr) =
// Section: Array Manipulation
// Section: List Iteration Helpers
// Function: subindex()
// Description:
// For each array item, return the indexed subitem.
// Returns a list of the values of each vector at the specfied
// index list or range. If the index list or range has
// only one entry the output list is flattened.
// Arguments:
// v = The given list of lists.
// idx = The index, list of indices, or range of indices to fetch.
// Example:
// v = [[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]];
// subindex(v,2); // Returns [3, 7, 11, 15]
// subindex(v,[2,1]); // Returns [[3, 2], [7, 6], [11, 10], [15, 14]]
// subindex(v,[1:3]); // Returns [[2, 3, 4], [6, 7, 8], [10, 11, 12], [14, 15, 16]]
function subindex(v, idx) = [
for(val=v) let(value=[for(i=idx) val[i]])
len(value)==1 ? value[0] : value
];
// Function: min_index()
// Function: idx()
// Usage:
// min_index(vals,[all]);
// i = idx(list);
// for(i=idx(list)) ...
// Description:
// Returns the index of the first occurrence of the minimum value in the given list.
// If `all` is true then returns a list of all indices where the minimum value occurs.
// Returns the range of indexes for the given list.
// Arguments:
// vals = vector of values
// all = set to true to return indices of all occurences of the minimum. Default: false
// Example:
// min_index([5,3,9,6,2,7,8,2,1]); // Returns: 4
// min_index([5,3,9,6,2,7,8,2,1],all=true); // Returns: [4,7]
function min_index(vals, all=false) =
all ? search(min(vals),vals,0) : search(min(vals), vals)[0];
// list = The list to returns the index range of.
// step = The step size to stride through the list. Default: 1
// end = The delta from the end of the list. Default: -1
// start = The starting index. Default: 0
// Example(2D):
// colors = ["red", "green", "blue"];
// for (i=idx(colors)) right(20*i) color(colors[i]) circle(d=10);
function idx(list, step=1, end=-1,start=0) =
assert(is_list(list)||is_string(list))
[start : step : len(list)+end];
// Function: max_index()
// Usage:
// max_index(vals,[all]);
// Function: enumerate()
// Description:
// Returns the index of the first occurrence of the maximum value in the given list.
// If `all` is true then returns a list of all indices where the maximum value occurs.
// Returns a list, with each item of the given list `l` numbered in a sublist.
// Something like: `[[0,l[0]], [1,l[1]], [2,l[2]], ...]`
// Arguments:
// vals = vector of values
// all = set to true to return indices of all occurences of the maximum. Default: false
// l = List to enumerate.
// idx = If given, enumerates just the given subindex items of `l`.
// Example:
// max_index([5,3,9,6,2,7,8,9,1]); // Returns: 2
// max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7]
function max_index(vals, all=false) =
all ? search(max(vals),vals,0) : search(max(vals), vals)[0];
// enumerate(["a","b","c"]); // Returns: [[0,"a"], [1,"b"], [2,"c"]]
// enumerate([[88,"a"],[76,"b"],[21,"c"]], idx=1); // Returns: [[0,"a"], [1,"b"], [2,"c"]]
// enumerate([["cat","a",12],["dog","b",10],["log","c",14]], idx=[1:2]); // Returns: [[0,"a",12], [1,"b",10], [2,"c",14]]
// Example(2D):
// colors = ["red", "green", "blue"];
// for (p=enumerate(colors)) right(20*p[0]) color(p[1]) circle(d=10);
function enumerate(l,idx=undef) =
assert(is_list(l)||is_string(list))
(idx==undef)?
[for (i=[0:1:len(l)-1]) [i,l[i]]] :
[for (i=[0:1:len(l)-1]) concat([i], [for (j=idx) l[i][j]])];
// Function: pair()
@ -912,6 +904,28 @@ function permute(l,n=2,_s=0) =
[for (i=[_s:1:len(l)-n], p=permute(l,n=n-1,_s=i+1)) concat([l[i]], p)];
// Section: Array Manipulation
// Function: subindex()
// Description:
// For each array item, return the indexed subitem.
// Returns a list of the values of each vector at the specfied
// index list or range. If the index list or range has
// only one entry the output list is flattened.
// Arguments:
// v = The given list of lists.
// idx = The index, list of indices, or range of indices to fetch.
// Example:
// v = [[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]];
// subindex(v,2); // Returns [3, 7, 11, 15]
// subindex(v,[2,1]); // Returns [[3, 2], [7, 6], [11, 10], [15, 14]]
// subindex(v,[1:3]); // Returns [[2, 3, 4], [6, 7, 8], [10, 11, 12], [14, 15, 16]]
function subindex(v, idx) = [
for(val=v) let(value=[for(i=idx) val[i]])
len(value)==1 ? value[0] : value
];
// Function: zip()
// Usage:
// zip(v1, v2, v3, [fit], [fill]);
@ -942,7 +956,7 @@ function zip(vecs, v2, v3, fit=false, fill=undef) =
(v3!=undef)? zip([vecs,v2,v3], fit=fit, fill=fill) :
(v2!=undef)? zip([vecs,v2], fit=fit, fill=fill) :
assert(in_list(fit, [false, "short", "long"]))
assert(all( [for(v=vecs) is_list(v)]), "One of the inputs to zip is not a vector")
assert(all([for(v=vecs) is_list(v)]), "One of the inputs to zip is not a list")
let(
minlen = list_shortest(vecs),
maxlen = list_longest(vecs),
@ -951,6 +965,7 @@ function zip(vecs, v2, v3, fit=false, fill=undef) =
[for(i=[0:1:maxlen-1]) [for(v=vecs) for(x=(i<len(v)? v[i] : (fill==undef)? [fill] : fill)) x] ] :
[for(i=[0:1:minlen-1]) [for(v=vecs) for(x=v[i]) x] ];
// Function: array_group()
// Description:
// Takes a flat array of values, and groups items in sets of `cnt` length.

View file

@ -8,7 +8,7 @@
//////////////////////////////////////////////////////////////////////
BOSL_VERSION = [2,0,76];
BOSL_VERSION = [2,0,77];
// Section: BOSL Library Version Functions