Merge pull request #1171 from adrianVmariano/master

Negative indexing in list_set and list_insert
This commit is contained in:
Revar Desmera 2023-05-17 23:50:10 -07:00 committed by GitHub
commit abf6f33185
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 32 deletions

View file

@ -377,7 +377,7 @@ function bselect(list,index) =
// Description:
// Generates a list of `n` copies of the given value `val`.
// If the count `n` is given as a list of counts, then this creates a
// multi-dimensional array, filled with `val`.
// multi-dimensional array, filled with `val`. If `n` is negative, returns the empty list.
// Arguments:
// val = The value to repeat to make the list or array.
// n = The number of copies to make of `val`. Can be a list to make an array of copies.
@ -386,6 +386,7 @@ function bselect(list,index) =
// b = repeat(8, [2,3]); // Returns [[8,8,8], [8,8,8]]
// c = repeat(0, [2,2,3]); // Returns [[[0,0,0],[0,0,0]], [[0,0,0],[0,0,0]]]
// d = repeat([1,2,3],3); // Returns [[1,2,3], [1,2,3], [1,2,3]]
// e = repeat(4, -1); // Returns []
function repeat(val, n, i=0) =
is_num(n)? [for(j=[1:1:n]) val] :
assert( is_list(n), "Invalid count number.")
@ -633,7 +634,9 @@ function list_pad(list, minlen, fill) =
// Description:
// Takes the input list and returns a new list such that `list[indices[i]] = values[i]` for all of
// the (index,value) pairs supplied and unchanged for other indices. If you supply `indices` that are
// beyond the length of the list then the list is extended and filled in with the `dflt` value.
// larger that the length of the list then the list is extended and filled in with the `dflt` value.
// If you specify indices smaller than zero then they index from the end, with -1 being the last element.
// Negative indexing does not wrap around: an error occurs if you give a value smaller than `-len(list)`.
// If you set `minlen` then the list is lengthed, if necessary, by padding with `dflt` to that length.
// Repetitions in `indices` are not allowed. The lists `indices` and `values` must have the same length.
// If `indices` is given as a scalar, then that index of the given `list` will be set to the scalar value of `values`.
@ -646,29 +649,45 @@ function list_pad(list, minlen, fill) =
// Example:
// a = list_set([2,3,4,5], 2, 21); // Returns: [2,3,21,5]
// b = list_set([2,3,4,5], [1,3], [81,47]); // Returns: [2,81,4,47]
function list_set(list=[],indices,values,dflt=0,minlen=0) =
function list_set(list=[],indices,values,dflt=0,minlen=0) =
assert(is_list(list))
!is_list(indices)? (
(is_finite(indices) && indices<len(list))
? concat([for (i=idx(list)) i==indices? values : list[i]], repeat(dflt, minlen-len(list)))
: list_set(list,[indices],[values],dflt)
) :
indices==[] && values==[]
!is_list(indices)?
assert(is_finite(indices))
let(
index = indices<0 ? indices+len(list) : indices
)
assert(index>=0, str("Index ",indices," is smaller than negative list length"))
(
index<len(list) ?
[
for(i=[0:1:index-1]) list[i],
values,
for(i=[index+1:1:len(list)-1]) list[i],
for(i=[len(list):1:minlen-1]) dflt
]
: concat(list, repeat(dflt, index-len(list)), [values], repeat(dflt, minlen-index-1))
)
: indices==[] && values==[]
? concat(list, repeat(dflt, minlen-len(list)))
: assert(is_vector(indices) && is_list(values) && len(values)==len(indices),
"Index list and value list must have the same length")
let( midx = max(len(list)-1, max(indices)) )
[
for (i=[0:1:midx]) let(
j = search(i,indices,0),
k = j[0]
)
assert( len(j)<2, "Repeated indices are not allowed." )
k!=undef
? values[k]
: i<len(list) ? list[i] : dflt,
each repeat(dflt, minlen-max(len(list),max(indices)))
];
: assert(is_vector(indices) && is_list(values) && len(values)==len(indices),
"Index list and value list must have the same length")
let( indices = [for(ind=indices) ind<0 ? ind+len(list) : ind],
midx = max(len(list)-1, max(indices))
)
assert(min(indices)>=0, "Index list contains value smaller than negative list length")
[
for (i=[0:1:midx])
let(
j = search(i,indices,0),
k = j[0]
)
assert( len(j)<2, "Repeated indices are not allowed." )
k!=undef ? values[k]
: i<len(list) ? list[i]
: dflt,
each repeat(dflt, minlen-max(len(list),max(indices)+1))
];
// Function: list_insert()
@ -679,7 +698,9 @@ function list_set(list=[],indices,values,dflt=0,minlen=0) =
// list = list_insert(list, indices, values);
// Description:
// Insert `values` into `list` before position `indices`. The indices for insertion
// are based on the original list, before any insertions have occurred.
// are based on the original list, before any insertions have occurred.
// You can use negative indices to count from the end of the list. Note that -1 refers
// to the last element, so the insertion will be *before* the last element.
// Arguments:
// list = list to insert items into
// indices = index or list of indices where values are inserted
@ -690,7 +711,9 @@ function list_set(list=[],indices,values,dflt=0,minlen=0) =
function list_insert(list, indices, values) =
assert(is_list(list))
!is_list(indices) ?
assert( is_finite(indices) && is_finite(values), "Invalid indices/values." )
assert(is_finite(indices), "Invalid indices." )
let(indices = indices<0 ? indices+len(list) : indices)
assert(indices>=0, "Index is too small, must be >= len(list)")
assert( indices<=len(list), "Indices must be <= len(list) ." )
[
for (i=idx(list)) each ( i==indices? [ values, list[i] ] : [ list[i] ] ),
@ -701,9 +724,13 @@ function list_insert(list, indices, values) =
"Index list and value list must have the same length")
assert( max(indices)<=len(list), "Indices must be <= len(list)." )
let(
indices = [for(ind=indices) ind<0 ? ind+len(list) : ind],
maxidx = max(indices),
minidx = min(indices)
) [
)
assert(minidx>=0, "Index list contains values that are too small")
assert(maxidx<=len(list), "Index list contains values that are too large")
[
for (i=[0:1:minidx-1] ) list[i],
for (i=[minidx : min(maxidx, len(list)-1)] )
let(

View file

@ -365,7 +365,7 @@ include <structs.scad>
// Example(2D,Med,NoAxes): Specifying by corner index. Use {{list_set()}} to construct the full chamfer cut list.
// path = star(47, ir=25, or=50); // long path, lots of corners
// chamfind = [8, 28, 60]; // But only want 3 chamfers
// chamfcut = list_set([],chamfind,[10,13,15],minlen=len(path)-1);
// chamfcut = list_set([],chamfind,[10,13,15],minlen=len(path));
// rpath = round_corners(path, cut=chamfcut, method="chamfer");
// polygon(rpath);
// Example(2D,Med,NoAxes): Two-pass to chamfer and round by index. Use {{repeat_entries()}} to correct for first pass chamfers.
@ -373,9 +373,9 @@ include <structs.scad>
// path = star(47, ir=32, or=65); // long path, lots of corners
// chamfind = [8, 28, 60]; // But only want 3 chamfers
// roundind = [7,9,27,29,59,61]; // And 6 roundovers
// chamfcut = list_set([],chamfind,[10,13,15],minlen=len(path)-1);
// roundcut = list_set([],roundind,repeat(8,6),minlen=len(path)-1);
// dups = list_set([], chamfind, repeat(2,len(chamfind)), dflt=1, minlen=len(path)-1);
// chamfcut = list_set([],chamfind,[10,13,15],minlen=len(path));
// roundcut = list_set([],roundind,repeat(8,6),minlen=len(path));
// dups = list_set([], chamfind, repeat(2,len(chamfind)), dflt=1, minlen=len(path));
// rpath1 = round_corners(path, cut=chamfcut, method="chamfer");
// rpath2 = round_corners(rpath1, cut=repeat_entries(roundcut,dups));
// polygon(rpath2);

View file

@ -160,7 +160,17 @@ module test_list_set() {
assert_equal(list_set([1,2,3], 1, 4, dflt=12, minlen=5), [1,4,3,12,12]);
assert_equal(list_set([1,2,3], [],[],dflt=12, minlen=5), [1,2,3,12,12]);
assert_equal(list_set([1,2,3], 5,9), [1,2,3,0,0,9]);
assert_equal(list_set([1,2,3], 5,9,dflt=12), [1,2,3,12,12,9]);
assert_equal(list_set([1,2,3], 5,9,minlen=4), [1,2,3,0,0,9]);
assert_equal(list_set([1,2,3], 5,9,minlen=7), [1,2,3,0,0,9,0]);
assert_equal(list_set([1,2,3], 5,9,dflt=12), [1,2,3,12,12,9]);
assert_equal(list_set([1,2,3], -1,12), [1,2,12]);
assert_equal(list_set([1,2,3], -1,12,minlen=5), [1,2,12,0,0]);
assert_equal(list_set([1,2,3], [-2,5], [8,9]), [1,8,3,0,0,9]);
assert_equal(list_set([1,2,3], [-2,5], [8,9],minlen=8,dflt=-1), [1,8,3,-1,-1,9,-1,-1]);
assert_equal(list_set([1,2,3], [-2,5], [8,9],minlen=3,dflt=-1), [1,8,3,-1,-1,9]);
assert_equal(list_set([1,2,3], [0],[4], minlen=5), [4,2,3,0,0]);
assert_equal(list_set([], 2,3), [0,0,3]);
assert_equal(list_set([], 2,3,minlen=5,dflt=1), [1,1,3,1,1]);
}
test_list_set();
@ -201,7 +211,6 @@ module test_list_remove_values() {
assert_equal(list_remove_values(test,99,all=true), test);
assert_equal(list_remove_values(test,[99,100],all=true), test);
assert_equal(list_remove_values(test,[99,100]), test);
}
test_list_remove_values();
@ -213,6 +222,8 @@ module test_list_insert() {
assert_equal(list_insert([3],[0,1], [1,2]), [1,3,2]);
assert_equal(list_insert([1,2,3],[],[]),[1,2,3]);
assert_equal(list_insert([], 0, 4),[4]);
assert_equal(list_insert([1,2,3],-2,4), [1,4,2,3]);
assert_equal(list_insert([1,2,3,4,5], [-1,-3],[12,9]), [1,2,9,3,4,12,5]);
}
test_list_insert();