The human animal differs from the lesser primates in his passion for lists.
— H. Allen Smith
Some naming conventions.

Let’s try to be clear…​ According to Wikipedia, we’re talking about an "Array data type, used in a programming language to specify a variable that can be indexed." I wholeheartedly concur, dear colleague.

Even though a vector, tuple, array and matrix are all, like Wikipedia said; "A variable that can be indexed", I like to reserve the word "Vector" for a tuple of no more than 3, sometimes homogenised to 4, elements, representing a point in 2D or 3D space, or a true vector in the mathematical sense. I use 'tuple' for a short list or a 'record', with 'simple' i.e: non-indexable elements. A list of values will be referred to as a 'tuple', a list of points or vectors (indexable themselves) will be named be an 'array'. An array may be multi-dimensional when it consists of a list of lists, like an array of profiles consisting of several points or 'vertices'.

Circular indexing

Circular indexing is when you consider the first element of an array to be the next of the last element. This makes array[12] valid even if the array only has 10 elements, and thus array[9] is the last, because you just keep numbering through, 10 becomes 0, 11 becomes 1 and thus array[12] is the same as array[2] (in this case). Now, even array[-2] has meaning; since array[0] is the first element and we consider it to be the next of the last element, array[-1] must be the last element, or array[len(array)-1], i.e. 'the first from the end' and thus array[-2] is the same as array[len(array)-2] or the 'second from the end'. It’s jolly handy; when you want to address the previous vertex of a polygon boundary; simply look at array[CurrentIndex-1] and whatever 'CurrentIndex' is, even if it’s the first element of the array, you’re looking at the previous vertex in the polygon. It’s a beauty, and jolly useful for mesh-generation and such like.

Important In The GHOUL, whenever a function takes index-parameters for an array or tuple (and even strings), the parameter will be mapped onto the valid range [0:len(MyList)-1] by Map() or, more likely, Dex() . Parameter names indicating this behaviour are: Index, Begin and End.

The Routines.

Indices, mapped to colors, displayed in an array.

Array

Check out the [Idex][Jdex][Kdex]–[X,Y,Z]–[R,G,B] parallel in the image. code See the code.

ArrayAdd()

ArrayAdd(Array,Additive)

  • Array, an array of any length, probably of scalars, or vertices…​

  • Additive, probably a scalar, or a vertex.

Add the same 'something' to each element in an array. This can be used also to translate an entire array of vertices by ArrayAdd()-ing a vector.

NewArray=ArrayAdd(Array=[[0,0],[1,5],[0,2],[3,7]],Additive=[1,2]);
echo(NewArray);

ECHO: [[1,2],[2,7],[1,4],[4,9]]

ArrayDomain()

ArrayDomain(Array)

  • Array, an array of vertices…​

Find the 'bounding box' or domain of a vertex-cloud. Returns a 'DomainVector'; an array of two tuples:

[[Xmin,Ymin,Zmin],[Xmax,Ymax,Zmax]]

All minimum coordinates are in the first [0] tuple, the maximums in the second [1] tuple. The two tuples contain the extreme coordinates of the vertex-cloud, but they are—​almost certainly—​not elements of the cloud. They are, however, two diametrically opposed corners of the bounding box within which all vertices of the cloud lie. The bounding box, being rectangular, has sides parallel to the coordinate axes. You want the smallest Y-coordinate in the vertex cloud? ArrayDomain(Array)[0].y tells you. If Array contains 2D vertices, they are automatically upgraded to 3D, the 'DomainVector' is always in 3D.

DV=ArrayDomain(Array=[[0,9],[1,5],[4,2],[3,7]]);
echo(DV);

ECHO: [[0,2,0],[2,7,0]]
Tip Did you know? Instead of 'DV[0][1]' or 'DV[0].y' you actually can do 'DV.x.y'. Who knew? We do, now…​

ArrayProduct()

ArrayProduct(Array,Start=0,End=-1)

  • Array, an array of scalars or vertices &c.

  • Start, index, first element to multiply, defaults to 0.

  • End, index, last element to multiply, defaults to Len(Array).

Multiply (a number of) successive elements of an array with each other. I needed this for the interrupted threads feature in Thread().

// 4x5x6=120
PP=ArrayProduct([0,1,2,3,4,5,6,7,8,9],Start=4,End=-4);
echo(PP);

ECHO: 120

ArraySelect()

ArraySelect(Array, Indices)

  • Array, array, array from which the 'sub-list' is selected.

  • Indices, indices, can be a list [2,5,8] or a range [2:7].

It’s not called SubArray() because, unlike SubString(), the selected elements don’t need to be successive, SubArray() can be found below.

Array=[a,b,c,d,e,f,g,h]
NewArr=ArraySelect(Array,[2,3,5]);
echo(NewArr);

ECHO: [c,d,f]

ArrayShift()

ArrayShift(Array,Shift)

  • Array, array.

  • Shift, integer, index of the element that will become the 0-indexed element, or, by how many indices the array elements get shifted left.

Negative Shift parameters will get mapped onto the valid index range; e.g. when Shift=-2, the element with index len(Array)-2 will become the new 0-indexed element .

Array=[0,1,2,3,4,5];

Arr1=ArrayShift(Array,3)
echo(Arr1);

ECHO: [3,4,5,0,1,2]

Arr2=ArrayShift(Array,-2)
echo(Arr1);

ECHO: [4,5,0,1,2,3]

ArraySum()

ArraySum(Array,Start,End)

  • Array, array, array of scalars, vectors, vertices &c. to be summed.

  • Start, integer, first element index.

  • End, integer, last element index.

Sum all elements of Array from Start to End inclusive.

echo(ArraySum([0,1,2,3,4,5],2,4));

ECHO: 9

CropArray()

CropArray(Array,Length=2)

  • Array, array of vertices, probably.

  • Length, length to which to crop the array elements. This is equivalent to len(), so the actual number of items left in the element.

The opposite (ish) of PadArray(), mainly used to demote an entire array of vertices to 2D.

NewArray=CropArray([[1,2,0],[2,3,0],[3,4,0]],2);
echo(NewArray);

ECHO: [[1,2],[2,3],[3,4]]

Dex()

Dex(Index,Max=$Len)

  • Index, integer, counter to be mapped onto [0:Max].

  • Max, integer, upper limit for the mapped result, usually Len() of the array under consideration.

There are many ways to 'circular address' an array, Dex() is probably the most elegant in The GHOUL. When Dex() is used multiple times on the same Array, define $Len=Len(Array); and use it like Array[Dex(SomeIndex)]. In the example below, notice how all multiples of 4 and -4, i.e., +-Max+1 return 0

Index=Dex(Anydex,3);       _  _  _  _
Anydex  :  -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8  9...
Index   :   3  0  1  2  3  0  1  2  3  0  1  2  3  0  1...

Find()

Find(Value,Array,Element=0,Condition="EQ",Find="First")

  • Value, what you’re looking to find.

  • Array, an array of values…​

  • Element, scalar, element of 2D array.

  • Condition, string, EQ, GT, GTE, LT, or LTE.

  • Find, string, First, Last, or All, determines whether the first, last or all matches are returned.

Find() is just a selector function for FindEQ(), FindGT(), FindGTE(), FindLT(), and FindLTE(), all of which can be called directly, see below.

Index=Find(2,[0,4,9,3,2,7,1],0,"EQ","First");
echo(Index);

ECHO: 4

FindEQ()

FindEQ(Value,Array,Element=0,Find="First")

  • Value, what you’re looking to find.

  • Array, an array of values…​

  • Element, scalar, element of 2D array.

  • Find, string, First, Last, or All, determines whether the first, last or all matches are returned. returned.

Returns the index of the first, last or all element(s) in Array, equal to Value, or undef if none exists. Works with 1D or 2D arrays, see also Find() above.

Index=FindEQ(4,[[1,2],[3,4]],[[5,6],[7,8]],1);
echo(Index);

ECHO: 1
Tip FindGT(), FindGTE(), FindLT(), and FindLTE() all function identically to FindEQ(), except for their logical operation, and are therefore not treated 'again' here.

FlattenArray()

FlattenArray(Array)

  • Array, an array of depth (or 'dimension') greater than 1.

'Flattens' or 'demotes' elements of Array by reducing the depth level by 1. Each element is 'stripped' of it’s outer brackets, scalars or atoms of depth '0' are left untouched. It’s important to know that levels are removed from the top of Array (from the outside in).

NewArray=FlattenArray([[[1,2],[3,4]],[[5,6],[7,8]]]);
echo(NewArray);

ECHO: [[1,2],[3,4],[5,6],[7,8]]

NewArray=FlattenArray([[[1],2],[[3],[4]],[[[5],6],7]]);
echo(NewArray);

ECHO: [[1], 2, [3], [4], [[5], 6], 7]

FlattenArray() is safe for strings.

NewArray=FlattenArray([0,1,[3,"Foo"],"Bar"]);
echo(NewArray);

ECHO: [0, 1, 3, "Foo", "Bar"]

GetValue()

GetValue(Key,KeyValueArray,Element=1)

  • Key, anything, item to be found.

  • KeyValueArray, array, where tho find Key.

  • Element, integer, index of element to return.

Search for a key in a key-value array and return the value of the requested element. Array must be an array of indexable variables, i.e. an array of tuples or vectors. GetValue() looks at the 0-indexed element of the array items to find the key. For clarity, when Element=1, and Array[SomeDex][0]=Key, Array[SomeDex][1] is returned.

Array=[["A",12,2],["B",1,7],["C",4,9],["D",14,8]];
Foo=GetValue("C",Array,1)
echo(Foo);

ECHO: 4

IsInArray()

IsInArray(Element,Array)

  • Element, a value or string-character.

  • Array, an array or string.

There is search(v,a)[0]!=undef, so why have IsInArray(v,a)? Sadly, the former displays some exasperatingly strange and unexpected behaviour with strings, whereas the latter doesn’t. The native OpenSCAD search() is both powerful, and horribly fickle—​besides displaying some worryingly bipolar behaviour—​and I really wish someone would have a good look at it, and whip it into shape…​

echo(IsInArray(5,[2,4,7,5,9,3]));
echo(IsInArray("s","dtsh"));

ECHO: true
ECHO: true

Last()

Last(Array)

  • Array, an array.

Returns the last value from an array, Last() really is just an 'alias' for Array[len(Array)-1]. It prettifies the code. I think.

There’s also the even less necessary First() included in 'Last.scad', because if you have Yin…​

LeftArray()

LeftArray(Array,End)

  • Array, array, array from which the 'sub-list' is selected.

  • End, integer, 0-based ID of last selected item.

End is re-mapped by Dex(), so you can do LeftArray(Array,-2) for all but the last item from Array.

Array=RangeToTuple([0:10]);
NewArr=LeftArray(Array,3);
NewerArr=LeftArray(Array,-2);
echo(NewArr);
echo(NewerArr);

ECHO: [0,1,2,3]

Len()

Len(Array)

  • Array, an array.

I just got sick of typing '-1'…​ Len(Array) returns len(Array)-1. It also doesn’t stumble over things like Len(5), you know, like len() used to before it was 'improved' with all those annoying warnings in the console. :O=

Match()

Match(Key,KeyArray,ValueArray,Element=0)

  • Key, anything, item to be found.

  • KeyArray, array, where tho find Key.

  • ValueArray, array, where tho find the requested value.

  • Element, integer, if ValueArray is an array of indexable variables, the index of value element to return.

Match() is GetValue() but with separate Key and Value arrays. It finds Key in one array, and returns the value of the item with the same index from another array.

KeyArray=["A","B","C","D"];
ValueArray=[[12,2],[1,7],[4,9],[14,8]];
Foo=Match("C",KeyArray,ValueArray,0)
echo(Foo);

ECHO: 4

Möbius

MoebiusArray()

MoebiusArray(Array,Index)

  • Array, an array.

  • Index, index of the element we want to address.

MoebiusArray() lets you address an array as if it were a closed loop, like a Möbius strip. Index can be any number, positive or negative; it is mapped onto [0:len(Array)-1], with 0⟶0. Useful for cycling through an array or addressing things like VertexArray[-5] for '5 items from the end' &c. Perfect for addressing vertices in closed curves or meshes.

I couldn’t resist the temptation to make an animated image for MoebiusArray(), the code is there too.

Array=[0,1,2,3,4,5,6,7,8,9];
NewVar=MoebiusArray(Array,-3);
echo(NewVar);

ECHO: 7
Tip MoebiusArray() was my first attempt at 'circular addressing', but it’s now just an alias for Map(), or, actually, for the latter’s specialised variant Dex(). The only reason I left MoebiusArray() in this most excellent documentation is that, because of it, I made that sexy Möbius strip, and I’m so chuffed with it, I need an excuse to put it here…​

So, after all that, use Dex(), not MoebiusArray().

Array=[0,1,2,3,4,5,6,7,8,9];
$Len=Len(Array);

Foo=Array[Dex(-5,Len(Array))];
Bar=Array[Dex(12)];
echo(Foo,Bar)

ECHO: 5,2

PadArray()

PadArray(Array,Length=3,Padding=0)

  • Array, an array of 2D vertices, probably.

  • Length, the desired element length.

  • Padding, the scalar to use for padding.

PadArray() can take an array of 2D vertices and 'promote them' all to 3D by adding a '0' Z-coordinate, or it can make an entire array of 3D vertices homogenous, or it can make all elements of Array of equal length if they are not…​

NewArray=PadArray([[0,1],[2,3]]);
echo(NewArray);

ECHO: [[0, 1, 0],[2, 3, 0]]

NewArray=PadArray([[0,1,3],[1,2]],4,undef);
echo(NewArray);

ECHO: [[0,1,2,undef],[1,2,undef,undef]]

QuickFind()

QuickFind(Value,Array)

  • Value, a variable.

  • Array, array, array to search for Value.

A quick searching routine for ordered arrays.

This routine performs 5x faster than a regular 'walk through' search. The reason? It halves the number of possibilities with each step, for example it searches a 1000 element array in less than 10 steps, since 1000/2^10<1.

It is only slightly slower than the native search(), an achievement in itself, but—​of course—​you should use search() and not QuickFind(). It’s only here because I love the working principle of this routine. It’s purdy.

QuickSort()

QuickSort(Array,Element)

  • Array, an array of scalars, strings or tuples.

QuickSort() sorts Array, quickly. For 2D arrays such as vertex lists, it can sort by a specific element, say the Y-coordinate of a vertex cloud.

echo(QuickSort([10,8.7,-5,-10,0,-8.7,5]);
ECHO: [-10, -8.7, -5, 0, 5, 8.7, 10]

echo(QuickSort(["r","tt","R","bla","b"]));
ECHO: ["R", "b", "bla", "r", "tt"]

echo(QuickSort([[1,2],[3,-1],[5,4],[8,0]],1));
ECHO: [[3,-1],[8,0],[1,2],[5,4]]

RemoveDoubles()

RemoveDoubles(Array,Closed=true)

  • Array, an array of 2D or 3D vertices.

  • Closed, a Boolean, if true, the curve is closed and Array[0] and Array[len(Array)-1] are also evaluated.

Remove consecutive identical elements in an array. This is required after concat() of e.g. curve segments as end and start points of successive curve segments may be identical. This routine also removes Array[n] if it is identical to Array[0] and Closed=true.

NewArray=RemoveDoubles([[1,2],[3,6],[2,10],[2,10],[-4,5],[1,2]],Closed=true);
echo(NewArray);

ECHO: [[1,2],[3,6],[2,10],[-4,5]]

RemoveRepeated()

RemoveRepeated(List)

  • List, array or string.

Removes all but the first occurrence of array elements or string characters.

echo(RemoveRepeated([1,2,3,3,4,5,6,7,4,8,5]));
ECHO: [1,2,3,4,5,6,7,8]

echo(RemoveRepeated("Abracadabra"));
ECHO: ["A", "b", "r", "a", "c", "d"]

echo(TupleToString(RemoveRepeated("Abracadabra")));
ECHO: "Abracd"

RemoveSuccessive()

RemoveSuccessive(Array)

  • Array, an array.

Like RemoveDoubles(), but unlike RemoveDoubles(), this routine does not remove the last value Array[n] if it is identical to Array[0].

RemoveUndefs()

RemoveUndefs(Array)

  • Array, an array.

Removes all elements equal to undef from an array.

ReverseArray()

ReverseArray(Array)

  • Array, an array.

Reverse an array. I don’t know why. Because you can. Just use Array[Len(Array)-Index] already.

RightArray()

RightArray(Array,Begin)

  • Array, array, array from which the 'sub-list' is selected.

  • Begin, integer, 0-based ID of first item to be selected.

Begin is re-mapped by Dex(), so you can do RightArray(Array,-2) for the last two items from Array.

Array=RangeToTuple([0:9]);
NewArr=RightArray(Array,3);
NewerArr=RightArray(Array,-2);
echo(NewArr);
echo(NewerArr);

ECHO: [3,4,5,6,7,8,9]
ECHO: [8,9]

RoundArray()

RoundArray(Array)

  • Array, an array.

Performs round() operation on all elements of an array.

ScaleArray()

ScaleArray(Array,ScaleVector)

  • Array, an array of vectors or vertices.

  • ScaleVector, vector, a vector of equal length as the elements of Array.

Scale an array of vertices by different factors for each dimension. An array can be scaled in all dimensions equally by simple multiplication with a scalar like 'NewArr=3*Array'

NewArr=ScaleArray([[1,2,3],[4,5,6],[7,8,9]],[1,2,3]);
echo(NewArr);

ECHO: [[1,4,9],[4,10,18],[7,16,27]]

SetArrayElement()

SetArrayElement(Array,Tuple,Element,Value)

  • Array, an array of vertices, probably.

  • Tuple, Array[Tuple].

  • Element, Array[Tuple[Element]].

  • Value, the new value for Array[Tuple[Element]].

SetArrayElement() will set the value of an individual array element.

OldArray=[[1, 2], [3, 4]];
NewArray=SetArrayElement(OldArray, 1, 0, 5);
echo(NewArray);

ECHO: [[1, 2], [5, 4]]

SmashArray()

function SmashArray(Array)

  • Array, an array of arrays of vertices.

SmashArray() reduces the depth of Array to 1.

NewArray=SmashArray([[[1,2,3],[1,2,3]],[[1,2,3],[1,2,3]]]);
echo(NewArray);

ECHO: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

Stepped()

Stepped(Value,Step=$fs)

  • Value, scalar.

  • Step, scalar.

Returns an array [0…​Value] in segments the size of Step, which defaults to $fs. The first and last values in the array are always 0 and Value. Step will be adjusted so that all steps are of one, equal size. If Step is negative, there will be abs(Step) steps.

// Output values cropped to two decimals for clarity.
NewVar=Stepped(5.2,0.7);
echo(NewVar);

ECHO: [0, 0.74, 1.48, 2.22, 2.97, 3.71, 4.45, 5.2]

NewVar=Stepped(5.2,-6);
echo(NewVar);

ECHO: [0, 0.87, 1.73, 2.6, 3.47, 4.33, 5.2]

SubArray()

SubArray(Array,Start=0,End=-1)

  • Array, array, array from which the 'sub-list' is selected.

  • Start, integer, 0-based ID of first selected item.

  • End, integer, 0-based ID of last selected item.

Start and End are re-mapped by Dex(), like in the other routines here

Array=RangeToTuple([0:10]);
NewArr=SubArray(Array,2,-2);
echo(NewArr);

ECHO: [2,3,4,5,6,7,8]

SumArrays()

SumArrays(Array1,Array2)

  • Array1 and Array 2, arrays of equal length, containing scalars or vectors.

Returns a new array containing the sums of the corresponding elements of the arrays.

NewArray=SumArrays([1,2,3,4,5],[1,2,3,4,5]);
echo(NewArray);

ECHO: [2,4,6,8,10]