303 lines
6.8 KiB
Plaintext
303 lines
6.8 KiB
Plaintext
/* array.cm - array creation and manipulation utilities */
|
|
|
|
var _isArray = Array.isArray
|
|
var _slice = Array.prototype.slice
|
|
var _push = Array.prototype.push
|
|
var _sort = Array.prototype.sort
|
|
var _keys = Object.keys
|
|
var _from = Array.from
|
|
|
|
function array(arg, arg2, arg3, arg4) {
|
|
// array(number) - create array of size with nulls
|
|
// array(number, initial_value) - create array with initial values
|
|
if (typeof arg == 'number') {
|
|
if (arg < 0) return null
|
|
var len = number.floor(arg)
|
|
var result = []
|
|
|
|
if (arg2 == null) {
|
|
result.length = 100
|
|
} else if (typeof arg2 == 'function') {
|
|
var arity = arg2.length
|
|
for (var i = 0; i < len; i++) {
|
|
result[i] = arity >= 1 ? arg2(i) : arg2()
|
|
}
|
|
} else {
|
|
for (var i = 0; i < len; i++) result[i] = arg2
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// array(array) - copy
|
|
// array(array, function, reverse, exit) - map
|
|
// array(array, another_array) - concat
|
|
// array(array, from, to) - slice
|
|
if (_isArray(arg)) {
|
|
if (arg2 == null) {
|
|
// Copy
|
|
return _slice.call(arg)
|
|
}
|
|
|
|
if (typeof arg2 == 'function') {
|
|
// Map
|
|
var fn = arg2
|
|
var reverse = arg3 == true
|
|
var exit = arg4
|
|
var result = []
|
|
|
|
if (reverse) {
|
|
for (var i = arg.length - 1; i >= 0; i--) {
|
|
var val = fn(arg[i], i)
|
|
if (exit != null && val == exit) break
|
|
result[i] = val
|
|
}
|
|
} else {
|
|
for (var i = 0; i < arg.length; i++) {
|
|
var val = fn(arg[i], i)
|
|
if (exit != null && val == exit) break
|
|
_push.call(result, val)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
if (_isArray(arg2)) {
|
|
// Concat
|
|
var result = _slice.call(arg)
|
|
for (var i = 0; i < arg2.length; i++) {
|
|
_push.call(result, arg2[i])
|
|
}
|
|
return result
|
|
}
|
|
|
|
if (typeof arg2 == 'number') {
|
|
// Slice
|
|
var from = arg2
|
|
var to = arg3
|
|
var len = arg.length
|
|
|
|
if (from < 0) from += len
|
|
if (to == null) to = len
|
|
if (to < 0) to += len
|
|
|
|
if (from < 0 || from > to || to > len) return null
|
|
|
|
return _slice.call(arg, from, to)
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
// array(object) - keys
|
|
if (typeof arg == 'object' && arg != null && !_isArray(arg)) {
|
|
if (arg instanceof Set) {
|
|
return _from(arg)
|
|
}
|
|
return _keys(arg)
|
|
}
|
|
|
|
// array(text) - split into grapheme clusters
|
|
// array(text, separator) - split by separator
|
|
// array(text, length) - dice into chunks
|
|
if (typeof arg == 'string') {
|
|
if (arg2 == null) {
|
|
// Split into grapheme clusters (simplified: split into characters)
|
|
var result = []
|
|
for (var i = 0; i < arg.length; i++) {
|
|
_push.call(result, arg[i])
|
|
}
|
|
return result
|
|
}
|
|
|
|
if (typeof arg2 == 'string') {
|
|
// Split by separator
|
|
return arg.split(arg2)
|
|
}
|
|
|
|
if (typeof arg2 == 'number') {
|
|
// Dice into chunks
|
|
var len = number.floor(arg2)
|
|
if (len <= 0) return null
|
|
var result = []
|
|
for (var i = 0; i < arg.length; i += len) {
|
|
_push.call(result, arg.substring(i, i + len))
|
|
}
|
|
return result
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
array.reduce = function(arr, fn, initial, reverse) {
|
|
if (!_isArray(arr)) return null
|
|
if (typeof fn != 'function') return null
|
|
|
|
var len = arr.length
|
|
|
|
if (initial == null) {
|
|
if (len == 0) return null
|
|
if (len == 1) return arr[0]
|
|
|
|
if (reverse == true) {
|
|
var acc = arr[len - 1]
|
|
for (var i = len - 2; i >= 0; i--) {
|
|
acc = fn(acc, arr[i])
|
|
}
|
|
return acc
|
|
} else {
|
|
var acc = arr[0]
|
|
for (var i = 1; i < len; i++) {
|
|
acc = fn(acc, arr[i])
|
|
}
|
|
return acc
|
|
}
|
|
} else {
|
|
if (len == 0) return initial
|
|
|
|
if (reverse == true) {
|
|
var acc = initial
|
|
for (var i = len - 1; i >= 0; i--) {
|
|
acc = fn(acc, arr[i])
|
|
}
|
|
return acc
|
|
} else {
|
|
var acc = initial
|
|
for (var i = 0; i < len; i++) {
|
|
acc = fn(acc, arr[i])
|
|
}
|
|
return acc
|
|
}
|
|
}
|
|
}
|
|
|
|
array.for = function(arr, fn, reverse, exit) {
|
|
if (!_isArray(arr)) return null
|
|
if (typeof fn != 'function') return null
|
|
|
|
if (reverse == true) {
|
|
for (var i = arr.length - 1; i >= 0; i--) {
|
|
var result = fn(arr[i], i)
|
|
if (exit != null && result == exit) return exit
|
|
}
|
|
} else {
|
|
for (var i = 0; i < arr.length; i++) {
|
|
var result = fn(arr[i], i)
|
|
if (exit != null && result == exit) return exit
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
array.find = function(arr, fn, reverse, from) {
|
|
if (!_isArray(arr)) return null
|
|
|
|
var len = arr.length
|
|
|
|
if (typeof fn != 'function') {
|
|
// Compare exactly
|
|
var target = fn
|
|
if (reverse == true) {
|
|
var start = from != null ? from : len - 1
|
|
for (var i = start; i >= 0; i--) {
|
|
if (arr[i] == target) return i
|
|
}
|
|
} else {
|
|
var start = from != null ? from : 0
|
|
for (var i = start; i < len; i++) {
|
|
if (arr[i] == target) return i
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
if (reverse == true) {
|
|
var start = from != null ? from : len - 1
|
|
for (var i = start; i >= 0; i--) {
|
|
if (fn(arr[i], i) == true) return i
|
|
}
|
|
} else {
|
|
var start = from != null ? from : 0
|
|
for (var i = start; i < len; i++) {
|
|
if (fn(arr[i], i) == true) return i
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
array.filter = function(arr, fn) {
|
|
if (!_isArray(arr)) return null
|
|
if (typeof fn != 'function') return null
|
|
|
|
var result = []
|
|
|
|
for (var i = 0; i < arr.length; i++) {
|
|
var val = fn(arr[i], i)
|
|
if (val == true) {
|
|
_push.call(result, arr[i])
|
|
} else if (val != false) {
|
|
return null
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
array.sort = function(arr, select) {
|
|
if (!_isArray(arr)) return null
|
|
|
|
var result = _slice.call(arr)
|
|
var keys = []
|
|
|
|
// Extract keys
|
|
for (var i = 0; i < result.length; i++) {
|
|
var key
|
|
if (select == null) {
|
|
key = result[i]
|
|
} else if (typeof select == 'string' || typeof select == 'number') {
|
|
key = result[i][select]
|
|
} else if (_isArray(select)) {
|
|
key = select[i]
|
|
} else {
|
|
return null
|
|
}
|
|
|
|
if (typeof key != 'number' && typeof key != 'string') return null
|
|
keys[i] = key
|
|
}
|
|
|
|
// Check all keys are same type
|
|
if (keys.length > 0) {
|
|
var keyType = typeof keys[0]
|
|
for (var i = 1; i < keys.length; i++) {
|
|
if (typeof keys[i] != keyType) return null
|
|
}
|
|
}
|
|
|
|
// Create index array and sort
|
|
var indices = []
|
|
for (var i = 0; i < result.length; i++) indices[i] = i
|
|
|
|
// Stable sort using indices
|
|
_sort.call(indices, function(a, b) {
|
|
if (keys[a] < keys[b]) return -1
|
|
if (keys[a] > keys[b]) return 1
|
|
return a - b // stable
|
|
})
|
|
|
|
var sorted = []
|
|
for (var i = 0; i < indices.length; i++) {
|
|
sorted[i] = result[indices[i]]
|
|
}
|
|
|
|
return sorted
|
|
}
|
|
|
|
return array
|