Array
The array is the default container type in HiseScript for holding multiple elements that can be accessed by their index. There are a few other container types which are better suited for particular workflows (see the section about Alternatives below), but for general data processing this is one of the most important concepts to know about.
Basic usage
const var a = []; // Declare an array
a[0] = 12; // Set the element at position 0 to 12
a[1] = "Hello"; // Set the element at position 1 to "Hello"
Console.print(a.length); // Print the length (in this case 2)
a.clear(); // Deletes all items from the array
If you have used another programming language before, this might look pretty familiar. Be aware that you can add / delete items from the array despite having it declared as const var
. The "constness" just refers to the assignment, so you can't reassign this variable to another value.
Iterating over an array
Basically there are two ways of iterating (= going over each element in the array):
Range-based Loop | Index-based Loop |
for(element in array)
|
for(i = 0; i < array.length; i++)
|
This is the preferred method, because it has a clearer syntax (and is faster). As long as you don't need to know the index of the element, it's recommended to use this method. | If you need the index of the current item in the loop (eg. because you iterate over multiple arrays at once), use this loop. |
The index based loop construct is the only place where you can define anonymous variables (so that for(i = 0...
doesn't throw a compile error).
Ownership & lifetime
An array is reference counted, which means that if you assign an array to another variable, it will use the same array.
const var a = [1, 5, 6];
const var b = a;
a[0] = 10; // set the first element of a
Console.print(b[0]); // the first element of b will also be 10
Alternatives
The Array is a very dynamic container type and can be resized at any time to make room for more elements. For UI and data processing this is an incredibly useful feature. However this flexibility makes it a very poor choice for whenever you want to do some MIDI processing logic which usually runs in the audio callback where allocating new memory is a no go.
In order to mitigate this problem, there are a bunch of other container types similar to the stock Array but with an emphasis on certain tasks within the realtime callback:
- Buffer is a densely packed, floating point array that represents audio signals
- MidiList is a object that holds 128 integer numbers and is particularly useful for holding MIDI information (eg. note numbers)
- FixObjectArray is a preallocated list of elements with a predefined memory structure and can be the most efficient solution for many tasks
- Unorderedstack is a stack that offers fast insertion / removal by ignoring the order of elements and is particularly useful for storing the information about currently played notes (where the order doesn't matter).
If you don't want to use those containers, you can of course use the Array in the MIDI processing context as long as you don't resize the container (which is why the Array.reserve() function is so importanta).
Class methods
clear
Clears the array.
Array.clear()
This is a quick operation (the allocated storage space will not be freed), so you can use it in a realtime callback.
const var arr = []; // Declare an array
// preallocate 10 elements, do this if you
// know how many elements you are about to insert
arr.reserve(10);
for(i = 0; i < 10; i++)
{
// Add an element to the end of the array
arr.push(Math.randInt(0, 1000);
}
Console.print(trace(arr)); // [ 523, 5, 76, 345, 765, 45, 977, 223, 44, 54]
arr.clear();
Console.print(trace(arr)); // []
concat
Concatenates (joins) two or more arrays
Array.concat(var argumentList)
This method combines two or more arrays. You can pass in any number of arrays which will be put at the end of the array. It ignores non-array argument elements.
const var arr1 = [0, 1, [2, 3, 4]];
// note how the array in the array is counted as a single element
Console.print(arr1.length); // 3
const var arr2 = [5, 6, 7];
const var arr3 = [8, 9, 10];
arr1.concat(arr2);
Console.print(trace(arr1)); // [0, 1, [2, 3, 4], 5, 6, 7]
arr1.concat(arr3);
// the arr1 already contains arr2
Console.print(trace(arr1)); // [0, 1, [2, 3, 4], 5, 6, 7, 8, 9, 10]
// set type to array
const var arr4 = [];
arr4.concat(arr2, arr3, 8726, [11, 12, 13]);
// non-array arguments get ignored // arguments can be arrays themselves
Console.print(trace(arr4)); // [5, 6, 7, 8, 9, 10, 11, 12, 13]
contains
Searches for the element in the array.
Array.contains(var elementToLookFor)
The Array.contains
method checks if an array includes a certain element. If the array contains the specified element, it returns true
,
otherwise it returns false
.elementToLookFor
is the element to search for within the array.
Example
const var fruits = ["apple", "banana", "mango", "orange"];
Console.print(fruits.contains("banana")); // true
Console.print(fruits.contains("grape")); // false
find
Returns the value of the first element that passes the function test.
Array.find(var testFunction, var optionalThisObject)
The test function you pass in can have up to 3 parameters:
- the first parameter will be the element you need to perform the check on
- the second parameter will be the index
- the third parameter will be the array itself
const var list = [ "Hello", "world", "HISE", "rules" ];
Console.print(list.find(function(element){ return element.contains("H");})); // Hello
Console.print(list.find(function(element){ return element.contains("HI");})); // HISE
Using this function can vastly decrease the amount of code you need to write. This is the same logic of the first call with a loop and a custom function to achieve the same thing.
const var list = [ "Hello", "world", "HISE", "rules" ];
function findH()
{
for(element in list)
{
if(element.contains("H"))
return element;
}
return undefined;
}
Console.print(findH()); // Hello
indexOf
Searches the array and returns the first index.
Array.indexOf(var elementToLookFor, int startOffset, int typeStrictness)
Return the index of the first occurence or -1
if the item can't be found.
const var a = [1, 5, 5];
a.indexOf(5); // will return 1
a.indexOf("5"); // will also return 1, the search is not type-strict.
insert
Inserts the given arguments at the firstIndex.
Array.insert(int firstIndex, var argumentList)
The Array.insert
method allows you to add an element at a specified firstIndex
in the array. It modifies the original array and shifts the elements after the specified index to the right allowing for greater control over the array's structure than using Array.push
or setting the element using the []
-operator.
Note that if you pass in an Array as new element, it will add the element as an array and not the individual elements, so you'll end up with an Array within an Array.
Example
const var numbers = [1, 2, 3, 4, 5];
numbers.insert(2, 10);
Console.print(trace(numbers)); // [1, 2, 10, 3, 4, 5]
numbers.insert(0, 20);
Console.print(trace(numbers)); // [20, 1, 2, 10, 3, 4, 5]
numbers.insert(numbers.length, 30);
Console.print(trace(numbers)); // [20, 1, 2, 10, 3, 4, 5, 30]
numbers.insert(3, [101, 102, 103]);
Console.print(trace(numbers));
isArray
Checks if the given variable is an array.
Array.isArray(var variableToTest)
A simple bool check whether the argument variable is an Array. Note that this function is not a method that you call on the object itself (because calling it on a non-array would not find the function).
Instead you'll call it with the generic syntax Array.isArray()
const var trustMeIAmAnArray = 0;
const var notAnArrayTooButNiceTryString = "[1, 2, 3, 4, 5]";
const var list = [1, 2, 3, 4];
Console.print(Array.isArray(notAnArrayTooButNiceTryString)); // false;
Console.print(Array.isArray(trustMeIAmAnArray)); // false
Console.print(Array.isArray(list)); // true (finally)
join
Joins the array into a string with the given separator.
Array.join(var separatorString)
This method is useful when you want to change the item list of some UI controls, for example a Combobox
.
const var list = ["item1", "item2", "item3"]; // Creates a list of all available samplemaps
const var box = Content.addComboBox("box", 0, 0); // Creates a combobox
box.set("items", list.join("\n")); // sets the list as items
The opposite of this method is String.split()
map
Creates a new array from calling a function for every array element.
Array.map(var testFunction, var optionalThisObject)
pop
Removes and returns the last element.
Array.pop()
This is useful for managing sequential input that you're keeping track of: history of played notes, velocities, custom undo history etc.
You might want to use it in conjunction with Array.push() in order to implement a stack logic with the array.
Note that there's a special container type if you need a stack that doesn't care about the order of elements.
const arr1 = [1, 2, 3];
arr1[4] = 5;
Console.print(arr1.pop()); // 5
// we didn't set the 4th element (index 3) so it'll be undefined
Console.print(arr1.pop()); // error: API call with undefined parameter
arr1[3] = 22;
Console.print(trace(arr1)); // [1, 2, 3, 22]
// we can check ourselves for errors in our logic in this case
if (isDefined(arr1.pop()
{
// do stuff
}
push
Adds the given element at the end and returns the size.
Array.push(var elementToInsert)
If you know that you are going to add multiple elements, you can call Array.reserve()
to preallocate the amount of elements and improve performance:
const var a = [];
// Uncomment this to see the performance improvement:
//a.reserve(100);
Console.start();
for(i = 0; i < 100; i++)
{
a.push(5);
}
Console.stop()
pushIfNotAlreadyThere
Adds the given element at the end and returns the size.
Array.pushIfNotAlreadyThere(var elementToInsert)
remove
Removes all instances of the given element.
Array.remove(var elementToRemove)
removeElement
Removes the element at the given position.
Array.removeElement(int index)
reserve
Reserves the space needed for the given amount of elements.
Array.reserve(int numElements)
If you are going to populate this array in a realtime callback, you need to make sure that there is enough storage allocated in order to avoid reallocation. This method can be used to preallocate slots that can be filled later.
Be aware that this method will not change the Array.length
property:
const var array = []; // create a new array
array.reserve(128); // allocate 128 items
Console.print(array.length) // will output 0;
array[64] = 190; // this will not allocate
Console.print(array.length) // will print 65
This method will allocate enough memory to hold primitive values, but if you are going to store complex objects (arrays or objects), calling Array.reserve()
will not prevent reallocation.
reverse
Reverses the order of the elements in the array.
Array.reverse()
sort
Sorts the array.
Array.sort()
This will sort the array using a sensible sort algorithm:
- Numbers will be sorted naturally,
- Strings will be sorted alphabetically
- Objects and arrays will not be sorted.
const var a = [1, 6, 4, 2, 1];
a.sort();
for(i in a)
Console.print(i);
// Result: 1, 1, 2, 4, 6
sortNatural
Sorts array of numbers, objects, or strings with "number in string" priority. Can also sort a combination of all types
Array.sortNatural()