#[no_std, cache_output] impl @array { is_empty: #[desc("Returns true if the array has a length of 0, false otherwise.") example(" arr = [] arr2 = [1, 2, 3] $.assert(arr.is_empty()) $.assert(!arr2.is_empty()) ")] (self) { return self.length == 0; }, max: #[desc("Gets the highest number in the array.") example(" arr = [3, 1, 4, 1] $.assert(arr.max() == 4) arr = ['abc', 'b', 'abdc'] $.assert(arr.max(key = (el: @string) => el.length) == 'abdc') ")] (self, key: @macro = (el) => el) { let highest = self[0] for el in self { if key(el) > key(highest) { highest = el } } return highest }, min: #[desc("Gets the lowest number in the array.") example(" arr = [3, 1, 4, 1] $.assert(arr.min() == 1) arr = ['abc', 'b', 'abdc'] $.assert(arr.max(key = (el: @string) => el.length) == 'b') ")] (self, key: @macro = (el) => el) { let lowest = self[0] for el in self { if key(el) < key(lowest) { lowest = el } } return lowest }, contains: #[desc("See if array contains an element.") example(" fruit = ['apple', 'banana', 'mango'] $.assert(arr.contains('banana')) ")] (self, el) { return self has el }, index: #[desc("Gets the index of an element (if it doesn't exist, `null` is returned)") example(" fruit = ['apple', 'banana', 'mango'] $.assert(fruit.index('apple') == 0) $.assert(fruit.index('carrot') == null) ")] (self, el, #[desc("Index to start the search from")] from: @number = 0) { for i in from..self.length { if self[i] == el { return i } } return null }, index_last: #[desc("Gets the index of the last occurence of an element (if it doesn't exist, `null` is returned)") example(" arr = [1,-5,2,4,2,6] $.assert(arr.index_last(2) == 4) $.assert(arr.index_last(-3) == null) ")] (self, el, #[desc("Index to end the search at")] until: @number = 0) { for i in self.length..until { if self[i] == el { return i } } return null }, index_all: #[desc("Returns an array of all occurences of an element") example(" arr = [1,-5,2,4,2,6] $.assert(arr.index_all(2) == [2,4]) ")] (self, el) { let occurences = [] for i in 0..self.length { if self[i] == el { occurences.push(i) } } return occurences }, clear: #[desc("Clears the array.") example(" let arr = [1, 2, 3] arr.clear() $.assert(arr.is_empty()) ")] (self) { self = [] }, reverse: #[desc("Reverses the array.") example(" let arr = [1, 2, 3] $.assert(arr.reverse() == [3, 2, 1]) ")] (self) { if self.length == 0 { return []; break } let ret = []; for i in 1..self.length { ret.push(self[-i]); } ret.push(self[0]); return ret; }, push: #[desc("Pushes a value to the end of the array.") example(" let arr = [1, 2, 3] arr.push(4) $.assert(arr == [1, 2, 3, 4]) ")] (self, value) { $.append(self, value) }, pop: #[desc("Removes the last value from the array and returns it.") example(" let arr = [1, 2, 3, 4] arr.pop() $.assert(arr == [1, 2, 3]) ")] (self) { return $.pop(self) }, remove: #[desc("Removes a specific index from the array and returns it.") example(" let arr = [1, 2, 3, 4, 5] arr.remove(3) $.assert(arr == [1, 2, 3, 5]) ")] (self, index: @number) { return $.remove_index(self, index) }, map: #[desc("Calls a defined callback function on each element of an array, and returns an array that contains the results.") example(" arr = [1, 2, 3, 4, 5] $.assert(arr.map(el => el * 2) == [2, 4, 6, 8, 10]) ")] (self, cb: @macro) { let output = []; for iter in self { output.push(cb(iter)); } return output; }, filter: #[desc("Returns the elements of an array that meet the condition specified in the callback function.") example(" arr = [1, 2, 3, 4, 5] $.assert(arr.filter(el => el > 3) == [4, 5]) ")] (self, cb: @macro) { let output = []; for iter in self { let r = cb(iter); if r.type != @bool { throw "Filter must return a boolean value"; } else if r { output.push(iter) } } return output }, reduce: #[desc("Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.") example(" arr = [1, 2, 3, 4, 5] sum = arr.reduce((acum, el) => acum + el) $.assert(sum == 15) ")] (self, cb: @macro) { let acum = self[0]; for iter in 1..self.length { acum = cb(acum, self[iter]); } return acum; }, any: #[desc("Determines whether the specified callback function returns true for any element of an array.") example(" arr = [false, false, true, false] $.assert(arr.any()) arr2 = [1, 2, 3, 1, 4, -1, 7] $.assert(arr2.any(el => el < 0)) // checks if the array contains any negative elements ")] (self, map: @macro = (a) => @bool(a)) { for item in self { if map(item) { return true } } return false }, all: #[desc("Determines whether all the members of an array satisfy the specified callback.") example(" arr = [true, true, true] $.assert(arr.all()) arr2 = [1, 2, 3, 1, 4, 7] $.assert(arr2.all(el => el > 0)) // checks if the array contains only positive elements ")] (self, map: @macro = (a) => @bool(a)) { for item in self { if !map(item) { return false } } return true }, sum: #[desc("Gets the sum of the value in the array.") example(" arr = [1, 2, 3, 4, 5] $.assert(arr.sum() == 15) ")] (self) { return self.reduce((acum, el) => acum + el) }, _partition: #[desc("Private function needed for .sort()")] (self, low: @number, high: @number, comp: @macro = (a, b) => a <= b) { pivot = self[high] let i = low - 1 for j in low..high { if comp(self[j], pivot) { i += 1 self[i] <=> self[j] } } self[i+1] <=> self[high] return i + 1 }, sort: #[desc("Sorts array in-place") example(" arr = [5, 1, 5, 3, 2] arr.sort() $.assert(arr == [1, 2, 3, 5, 5]) arr = [5, 1, 5, 3, 2] arr.sort(begin = 2, end = 4) $.assert(arr == [5, 1, 2, 3, 5]) arr = [5, 1, 5, 3, 2] arr.sort(comp = (a, b) => a > b) $.assert(arr == [5, 5, 3, 2, 1]) ")] (self, begin: @number = 0, end: @number = -1, comp: @macro = (a, b) => a <= b) { // when end == -1, that means the end of the array, but comparing to -1 doesnt work so switch it back to legnth - 1 let new_end = end if end == -1 { new_end = self.length - 1 } // uses quick sort // no type checking becuase theoretically this can sort anything if it hasthe right comparator // if sort was overloaded we could have two seperate implementations if begin < new_end { let q = self._partition(low = begin, high = new_end, comp = comp) self.sort(begin = begin, end = q-1, comp = comp) self.sort(begin = q+1, end = new_end, comp = comp) } }, sorted: #[desc("Returns a sorted verison of the array") example(" arr = [5, 1, 5, 3, 2] $.assert(arr.sorted() == [1, 2, 3, 5, 5]) $.assert(arr.sorted(begin = 2, end = 4) == [5, 1, 2, 3, 5]) $.assert(arr.sorted(comp = (a, b) => a >= b) == [5, 5, 3, 2, 1]) ")] (self, begin: @number = 0, end: @number = -1, comp: @macro = (a, b) => a <= b) { let new_arr = self new_arr.sort(begin,end,comp) return new_arr }, shift: #[desc("Removes the first index from the array and returns it.") example(" let arr = [5, 1, 5, 3, 2] $.assert(arr.shift() == 5) $.assert(arr == [1, 5, 3, 2]) ")] (self) { return self.remove(0) }, unshift: #[desc("Pushes a value to the start of the array and returns it.") example(" let arr = [1, 5, 3, 2] $.assert(arr.unshift(5) == 5) $.assert(arr == [5, 1, 5, 3, 2]) ")] (self, value) { self = [value] + self return value }, flatten: #[desc("Flattens any sub-arrays into one big array.") example(" arr = [1, 2, [3, 4], 5, [6, 7, [8]]] $.assert(arr.flatten() == [1, 2, 3, 4, 5, 6, 7, 8]) ")] (self) { let output = []; for elem in self { if elem.type != @array { output.push(elem) } else { for i in elem.flatten() { output.push(i) } } } return output }, enumerate: #[desc("Returns an array of index-element pairs") example(" arr = [\"a\",\"b\",\"c\"] for i in arr.enumerate() { $.print(i[0], \": \", i[1]) } /* output: 0: 'a' 1: 'b' 2: 'c' */ ")] (self, #[desc("Return the pair as a dictionary")] dict: @bool = false) { if dict { return @array(..self.length).map(i => {index: i, value: self[i]}) } return @array(..self.length).map(i => [i, self[i]]) }, }