Array Library
The array library provides functionality for creating and manipulating arrays. Most of these functions are accessible as methods of array objects. There are a few functions which are called through the "array" namespace.
Table of Contents
- array.new(size: int [, fill])
- array.range(val1: int [, val2: int [, step: int]])
- Methods
- a.sort([how: function|string])
- a.reverse()
- a.dup()
- a.opApply([reverse: string])
- a.expand()
- a.toString()
- a.apply(func: function)
- a.map(func: function)
- a.reduce(func: function)
- a.each(func: function)
- a.filter(func: function)
- a.find(value)
- a.findIf(pred: function)
- a.bsearch(value)
- a.pop([index: int = -1])
- a.set(vararg)
- a.min()
- a.max()
- a.extreme(pred: function)
- a.all([pred: function])
- a.any([pred: function])
- a.fill(value)
- a.append(vararg)
- a.flatten()
- a.makeHeap()
- a.pushHeap(value)
- a.popHeap()
- a.sortHeap()
- a.count(value [, pred: function])
- a.countIf(pred: function)
Changes from MiniD 1
The following functions have been added:
- findIf
- set
- min
- max
- extreme
- all
- any
- fill: this takes the place of the slice-fill behavior ("a[] = 5") that was dropped.
- append
- flatten
- makeHeap
- pushHeap
- popHeap
- sortHeap
- count
- countIf
The length function has been removed since this is now covered by the length operator.
array.new(size: int [, fill])
You can use array literals to create small arrays in MiniD, but sometimes you just need to be able to create an array of arbitrary size. This function will create an array of the given size. If you pass a value for the fill parameter, the new array will have every element set to it. Otherwise, it will be filled with null.
array.range(val1: int [, val2: int [, step: int]])
Creates a new array filled with integer values specified by the arguments. This is similar to the Python range() function, but is a little more intelligent when it comes to the direction of the range. Namely, if you give it indices where the ending index is less than the beginning, it will automatically use a negative step. In fact, the step value passed to this function must always be greater than 0; it simply defines the size of the step regardless of the direction the range goes in.
If only one argument is given, that argument specifies the noninclusive ending index, and the beginning index is assumed to be 0 and the step to be 1. This means array.range(5) will return [0, 1, 2, 3, 4] and array.range(-5) will return [0, -1, -2, -3, -4].
If two arguments are given, the first is the beginning inclusive index and the second is the ending noninclusive index. The step is again assumed to be 1. Examples: array.range(3, 8) yields [3, 4, 5, 6, 7]; array.range(2, -2) yields [2, 1, 0, -1]; and array.range(-10, -7) yields [-10, -9, -8].
Lastly, if three arguments are given, the first is the beginning inclusive index, the second the ending noninclusive index, and the third the step value. The step must be greater than 0; this function will automatically figure out that it needs to subtract the step if the ending index is less than the beginning index. Example: array.range(1, 20, 4) yields [1, 5, 9, 13, 17] and array.range(10, 0, 2) yields [10, 8, 6, 4, 2].
Methods
These are all called as "a.methodname()", where "a" is any array object.
a.sort([how: function|string])
Sorts the given array. All the elements must be comparable with one another. Will call any opCmp metamethods. Returns the array itself.
If no parameters are given, sorts the array in ascending order.
If the optional how parameter is given the string "reverse", the array will be sorted in descending order.
If the how parameter is a function, it is treated as a sorting predicate. It should take two arguments, compare them, and return an ordering integer (i.e. negative if the first is less than the second, positive if the first is greater than the second, and 0 if they are equal).
Changes from MiniD 1
Added the how parameter.
a.reverse()
Reverses the elements in the given array in-place. Returns the array itself.
a.dup()
Creates a copy of the given array. Only the array elements are copied, not any data that they point to.
a.opApply([reverse: string])
This allows you to iterate over arrays using foreach loops.
foreach(i, v; a) // ... foreach(i, v; a, "reverse") // iterate backwards
As the second example shows, passing in the string "reverse" as the second parameter will cause the iteration to run in reverse.
a.expand()
Returns all the elements of the array in order. In this way, you can "unpack" an array's values to pass as separate parameters to a function, or as return values, etc. Note that you probably shouldn't use this on really big arrays.
a.toString()
Returns a nice string representation of the array. This will format the array into a string that looks like a MiniD expression, like "[1, 2, 3]". Note that the elements of the array do not have their toString metamethods called, since that could lead to infinite loops if the array references itself directly or indirectly. To get a more complete representation of an array, look at the baselib dumpVal function (though that only outputs to the console).
a.apply(func: function)
Iterates over the array, calling the function with each element of the array, and assigns the result of the function back into the corresponding array element. The function should take one value and return one value. Returns the array it was called on. This works in-place, modifying the array on which it was called. As an example, "[1, 2, 3, 4, 5].map(\x -> x * x)" will replace the values in the array with "[1, 4, 9, 16, 25]".
a.map(func: function)
Like apply, but creates a new array and puts the output of the function in there, rather than modifying the source array. Returns the new array.
a.reduce(func: function)
If the given array's length is 0, returns null. If the length is 1, returns the first element. Otherwise, calls the function with the first two elements as the parameters, gets that result, then calls the function with that result and the third element, gets that result, calls the function with that result and the fourth parameter... This continues until all the elements in the array have been iterated over. This seems confusing, but makes sense with a bit of illustration: "[1, 2, 3, 4, 5].reduce(\(a, b) -> a + b)" will sum all the elements of the array, since it's like writing ((((1 + 2) + 3) + 4) + 5). The first two elements are added, then the result is added to the third, and so on. The result of this function is the result of the application of the function to all the elements.
a.each(func: function)
Similar to table.each, this is an alternate way of iterating over an array. The function is called once for each element, starting at the first element. The parameters to the function are the array as the context, then the index, and then the value. If the function returns false, iteration will stop and this function will return. This function returns the array on which it was called.
a.filter(func: function)
Creates a new array which holds only those elements for which the given function returned true when called with elements from the source array. The function is passed two arguments, the index and the value, and should return a boolean value. true means the given element should be included in the result, and false means it should be skipped. "[1, 2, "hi", 4.5, 6].filter(\(i, v) -> isInt(v))" would result in the array "[1, 2, 6]", as the filter function only returns true for integral elements.
a.find(value)
Performs a linear search for the value in the array. Returns the length of the array if it wasn't found, or its index if it was.
Changes from MiniD 1
Now returns the length of the array instead of -1 if the element is not found.
a.findIf(pred: function)
Similar to find except that it uses a predicate instead of looking for a value. Performs a linear search of the array, calling the predicate on each value. Returns the index of the first value for which the predicate returns true. Returns the length of the array if no value is found that satisfies the predicate.
a.bsearch(value)
Performs a binary search for the value in the array. Because of the way binary search works, the array must be sorted for this search to work properly. Additionally, all the elements must be comparable (they had to be for the sort to work in the first place). Returns the array's length if the value wasn't found, or its index if it was.
Changes from MiniD 1
Now returns the length of the array instead of -1 if the element is not found.
a.pop([index: int = -1])
This function can make it easy to use an array as a stack. Called with no parameters, it will remove the last element of the array and return it. Called with an index (which can be negative to mean from the end of the array), it will remove that element and shift all the other elements after it down a slot. In either case, if the array's length is 0, an error will be thrown.
a.set(vararg)
Kind of like the inverse of expand, this takes a variadic number of parameters, sets the length of the array to as many parameters as there are, and fills the array with those parameters. This is very similar to using an array constructor, but it reuses an array instead of creating a new one, which can save a lot of memory and time if you're doing this a lot.
a.min()
Gets the smallest value in the array. All elements of the array must be comparable to each other for this to work. Throws an error if the array is empty. If the array only has one value, returns that value.
a.max()
Gets the largest value in the array. All elements of the array must be comparable to each other for this to work. Throws an error if the array is empty. If the array only has one value, returns that value.
a.extreme(pred: function)
This is a generic version of min and max. Takes a predicate which should take two parameters: a new value, and the current extreme. The predicate should return true if the new value is more extreme than the current extreme, and false otherwise. To illustrate, "[1, 2, 3, 4, 5].extreme(\(new, extreme) -> new > extreme)" will do the same thing as max, since the predicate returns true if the value is bigger than the current extreme. (However, the min and max functions are optimized and will be faster than if you pass your own predicate.)
Throws an error if the array is empty. If the array only has one value, returns that value.
a.all([pred: function])
This is a generalized boolean "and" (logical conjunction) operation.
If called with no predicate function, returns true if every element in the array has a truth value of true, and false otherwise.
If called with a predicate, returns true if the predicate returned true for every element in the array, and false otherwise.
Returns true if called on an empty array.
a.any([pred: function])
This is a generalized boolean "or" (logical disjunction) operation.
If called with no predicate function, returns true if any element in the array has a truth value of true, and false otherwise.
If called with a predicate, returns true if the predicate returned true for any element in the array, and false otherwise.
Returns false if called on an empty array.
a.fill(value)
Sets every element in the array to the given value.
a.append(vararg)
Appends all the arguments to the end of the array, in order. This is different from the append operator (~=), because arrays will be appended as a single value, instead of having their elements appended.
a.flatten()
Flattens a multi-dimensional array into a single-dimensional array. The dimensions can be nested arbitrarily deep. If an array is directly or indirectly circularly referenced, throws an error. Always returns a new array. Can be called on single-dimensional arrays too, in which case it just returns a duplicate of the array.
a.makeHeap()
Reorders the elements of the given array so that they obey the heap property. Puts the largest item in the array at the head of the heap. The head is always a[0]. Returns the array.
Once an array has been "heaped", you can use the other heap functions on it. If you use one of those functions without first heaping the array, arbitrary behavior will result.
(note to self: these heap functions really should take predicates.)
a.pushHeap(value)
Push a value onto a heaped array. Returns the array.
a.popHeap()
Remove the head of the heaped array (the largest value in the heap) and return it. Throws an error if the array is empty.
a.sortHeap()
Sorts a heaped array. Calling makeHeap followed by sortHeap on an array will effectively sort it using heapsort.
a.count(value [, pred: function])
Called with just a value, returns the number of elements in the array that are equal to that value (according, optionally, to any opCmp overloads). If called with a predicate, the predicate should take two parameters. The second parameter will always be the value that is being counted, the first parameter will be values from the array. The predicate should return a bool telling whether that value of the array should be counted. Returns the number of elements for which the predicate returned true.
a.countIf(pred: function)
Similar to count, takes a predicate that should take a value and return a bool telling whether or not to count it. Returns the number of elements for which the predicate returned true.
