¶ ARRAYCopyright(c) 2013 Stefano Balietti MIT Licensed Collection of static functions to manipulate arrays. |
(function(JSUS) {
function ARRAY(){}; |
¶ ARRAY.filterAdd the filter method to ARRAY objects in case the method is not supported natively. |
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisp */) {
"use strict";
if (this === void 0 || this === null) throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function") throw new TypeError();
var res = [];
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in t) {
var val = t[i]; // in case fun mutates this
if (fun.call(thisp, val, i, t)) {
res.push(val);
}
}
}
return res;
};
} |
¶ ARRAY.isArrayReturns TRUE if a variable is an Array This method is exactly the same as Params
o
object
The variable to check.
See
Array.isArray
|
ARRAY.isArray = function(o) {
if (!o) return false;
return Object.prototype.toString.call(o) === '[object Array]';
}; |
¶ ARRAY.seqReturns an array of sequential numbers from start to end If start > end the series goes backward. The distance between two subsequent numbers can be controlled by the increment parameter. When increment is not a divider of Abs(start - end), end will be missing from the series. A callback function to apply to each element of the sequence can be passed as fourth parameter. Returns FALSE, in case parameters are incorrectly specified Params
start
number
The first element of the sequence
end
number
The last element of the sequence
increment
number
Optional. The increment between two
subsequents element of the sequence
func
Function
Optional. A callback function that can modify
each number of the sequence before returning it
Returns
array
out The final sequence
|
ARRAY.seq = function(start, end, increment, func) {
var i;
if ('number' !== typeof start) return false;
if (start === Infinity) return false;
if ('number' !== typeof end) return false;
if (end === Infinity) return false;
if (start === end) return [start];
if (increment === 0) return false;
if (!JSUS.in_array(typeof increment, ['undefined', 'number'])) {
return false;
}
increment = increment || 1;
func = func || function(e) {return e;};
i = start,
out = [];
if (start < end) {
while (i <= end) {
out.push(func(i));
i = i + increment;
}
}
else {
while (i >= end) {
out.push(func(i));
i = i - increment;
}
}
return out;
}; |
¶ ARRAY.eachExecutes a callback on each element of the array If an error occurs returns FALSE. Params
array
array
The array to loop in
func
Function
The callback for each element in the array
context
object
Optional. The context of execution of the
callback. Defaults ARRAY.each
Returns
Boolean
TRUE, if execution was successful
|
ARRAY.each = function(array, func, context) {
if ('object' !== typeof array) return false;
if (!func) return false;
context = context || this;
var i, len = array.length;
for (i = 0 ; i < len; i++) {
func.call(context, array[i]);
}
return true;
}; |
¶ ARRAY.mapApplies a callback function to each element in the db, store the results in an array and returns it Any number of additional parameters can be passed after the callback function Returns
array
out The result of the mapping execution
See
ARRAY.each
|
ARRAY.map = function() {
if (arguments.length < 2) return;
var args = Array.prototype.slice.call(arguments),
array = args.shift(),
func = args[0];
if (!ARRAY.isArray(array)) {
JSUS.log('ARRAY.map() the first argument must be an array. ' +
'Found: ' + array);
return;
}
var out = [],
o = undefined;
for (var i = 0; i < array.length; i++) {
args[0] = array[i];
o = func.apply(this, args);
if ('undefined' !== typeof o) out.push(o);
}
return out;
}; |
¶ ARRAY.removeElementRemoves an element from the the array, and returns it For objects, deep equality comparison is performed through JSUS.equals. If no element is removed returns FALSE. Params
needle
mixed
The element to search in the array
haystack
array
The array to search in
Returns
mixed
The element that was removed, FALSE if none was removed
See
JSUS.equals
|
ARRAY.removeElement = function(needle, haystack) {
var func, i;
if ('undefined' === typeof needle || !haystack) return false;
if ('object' === typeof needle) {
func = JSUS.equals;
}
else {
func = function(a,b) {
return (a === b);
}
}
for (i = 0; i < haystack.length; i++) {
if (func(needle, haystack[i])){
return haystack.splice(i,1);
}
}
return false;
}; |
¶ ARRAY.inArrayReturns TRUE if the element is contained in the array, FALSE otherwise For objects, deep equality comparison is performed through JSUS.equals. Alias ARRAY.in_array (deprecated) Params
needle
mixed
The element to search in the array
haystack
array
The array to search in
Returns
Boolean
TRUE, if the element is contained in the array
@see JSUS.equals
|
ARRAY.inArray = ARRAY.in_array = function(needle, haystack) {
if (!haystack) return false;
var func = JSUS.equals;
for (var i = 0; i < haystack.length; i++) {
if (func.call(this, needle, haystack[i])) {
return true;
}
} |
return false;
}; |
|
¶ ARRAY.getNGroupsReturns an array of N array containing the same number of elements If the length of the array and the desired number of elements per group are not multiple, the last group could have less elements The original array is not modified. @see ARRAY.getGroupsSizeN @see ARRAY.generateCombinations @see ARRAY.matchN Params
array
array
The array to split in subgroups
N
number
The number of subgroups
Returns
array
Array containing N groups
|
ARRAY.getNGroups = function(array, N) {
return ARRAY.getGroupsSizeN(array, Math.floor(array.length / N));
}; |
¶ ARRAY.getGroupsSizeNReturns an array of array containing N elements each The last group could have less elements Params
array
array
The array to split in subgroups
N
number
The number of elements in each subgroup
Returns
array
Array containing groups of size N
See
ARRAY.getNGroups
See
ARRAY.generateCombinations
See
ARRAY.matchN
|
ARRAY.getGroupsSizeN = function(array, N) {
var copy = array.slice(0);
var len = copy.length;
var originalLen = copy.length;
var result = [];
|
Init values for the loop algorithm. |
var i, idx;
var group = [], count = 0;
for (i=0; i < originalLen; i++) {
|
Get a random idx between 0 and array length. |
idx = Math.floor(Math.random()*len);
|
Prepare the array container for the elements of a new group. |
if (count >= N) {
result.push(group);
count = 0;
group = [];
}
|
Insert element in the group. |
group.push(copy[idx]);
|
Update. |
copy.splice(idx,1);
len = copy.length;
count++;
}
|
Add any remaining element. |
if (group.length > 0) {
result.push(group);
}
return result;
}; |
¶ ARRAY._latinSquareGenerate a random Latin Square of size S If N is defined, it returns "Latin Rectangle" (SxN) A parameter controls for self-match, i.e. whether the symbol "i" is found or not in in column "i". API
private
Params
S
number
The number of rows
Optional.
number
N The number of columns. Defaults N = S
Optional.
boolean
If TRUE self-match is allowed. Defaults TRUE
Returns
array
The resulting latin square (or rectangle)
|
ARRAY._latinSquare = function(S, N, self) {
self = ('undefined' === typeof self) ? true : self; |
Infinite loop. |
if (S === N && !self) return false;
var seq = [];
var latin = [];
for (var i=0; i< S; i++) {
seq[i] = i;
}
var idx = null;
var start = 0;
var limit = S;
var extracted = [];
if (!self) {
limit = S-1;
}
for (i=0; i < N; i++) {
do {
idx = JSUS.randomInt(start,limit);
}
while (JSUS.in_array(idx, extracted));
extracted.push(idx);
if (idx == 1) {
latin[i] = seq.slice(idx);
latin[i].push(0);
}
else {
latin[i] = seq.slice(idx).concat(seq.slice(0,(idx)));
}
}
return latin;
}; |
¶ ARRAY.latinSquareGenerate a random Latin Square of size S If N is defined, it returns "Latin Rectangle" (SxN) Params
S
number
The number of rows
Optional.
number
N The number of columns. Defaults N = S
Returns
array
The resulting latin square (or rectangle)
|
ARRAY.latinSquare = function(S, N) {
if (!N) N = S;
if (!S || S < 0 || (N < 0)) return false;
if (N > S) N = S;
return ARRAY._latinSquare(S, N, true);
}; |
¶ ARRAY.latinSquareNoSelfGenerate a random Latin Square of size Sx(S-1), where in each column "i", the symbol "i" is not found If N < S, it returns a "Latin Rectangle" (SxN) Params
S
number
The number of rows
Optional.
number
N The number of columns. Defaults N = S-1
Returns
array
The resulting latin square (or rectangle)
|
ARRAY.latinSquareNoSelf = function(S, N) {
if (!N) N = S-1;
if (!S || S < 0 || (N < 0)) return false;
if (N > S) N = S-1;
return ARRAY._latinSquare(S, N, false);
} |
¶ ARRAY.generateCombinationsGenerates all distinct combinations of exactly r elements each Params
array
array
The array from which the combinations are extracted
r
number
The number of elements in each combination
Returns
array
The total sets of combinations
See
ARRAY.getGroupSizeN
See
ARRAY.getNGroups
See
ARRAY.matchN
|
ARRAY.generateCombinations = function(array, r) {
function values(i, a) {
var ret = [];
for (var j = 0; j < i.length; j++) ret.push(a[i[j]]);
return ret;
}
var n = array.length;
var indices = [];
for (var i = 0; i < r; i++) indices.push(i);
var final = [];
for (var i = n - r; i < n; i++) final.push(i);
while (!JSUS.equals(indices, final)) {
callback(values(indices, array));
var i = r - 1;
while (indices[i] == n - r + i) i -= 1;
indices[i] += 1;
for (var j = i + 1; j < r; j++) indices[j] = indices[i] + j - i;
}
return values(indices, array);
}; |
¶ ARRAY.matchNMatch each element of the array with N random others If strict is equal to true, elements cannot be matched multiple times. Important: this method has a bug / feature. If the strict parameter is set, the last elements could remain without match, because all the other have been already used. Another recombination would be able to match all the elements instead. Params
array
array
The array in which operate the matching
N
number
The number of matches per element
strict
Boolean
Optional. If TRUE, matched elements cannot be
repeated. Defaults, FALSE
Returns
array
result The results of the matching
See
ARRAY.getGroupSizeN
See
ARRAY.getNGroups
See
ARRAY.generateCombinations
|
ARRAY.matchN = function(array, N, strict) {
var result, i, copy, group;
if (!array) return;
if (!N) return array;
result = [],
len = array.length,
found = [];
for (i = 0 ; i < len ; i++) { |
Recreate the array. |
copy = array.slice(0);
copy.splice(i,1);
if (strict) {
copy = ARRAY.arrayDiff(copy,found);
}
group = ARRAY.getNRandom(copy,N); |
Add to the set of used elements. |
found = found.concat(group); |
Re-add the current element. |
group.splice(0,0,array[i]);
result.push(group);
|
Update. |
group = [];
}
return result;
}; |
¶ ARRAY.repAppends an array to itself a number of times and return a new array The original array is not modified. Params
array
array
the array to repeat
times
number
The number of times the array must be appended
to itself
Returns
array
A copy of the original array appended to itself
|
ARRAY.rep = function(array, times) {
var i, result;
if (!array) return;
if (!times) return array.slice(0);
if (times < 1) {
JSUS.log('times must be greater or equal 1', 'ERR');
return;
}
i = 1, result = array.slice(0);
for (; i < times; i++) {
result = result.concat(array);
}
return result;
}; |
¶ ARRAY.stretchRepeats each element of the array N times N can be specified as an integer or as an array. In the former case all
the elements are repeat the same number of times. In the latter, each
element can be repeated a custom number of times. If the length of the
The original array is not modified. E.g.:
Params
array
array
the array to strech
times
number
array
The number of times each element
must be repeated
Returns
array
A stretched copy of the original array
|
ARRAY.stretch = function(array, times) {
var result, i, repeat, j;
if (!array) return;
if (!times) return array.slice(0);
if ('number' === typeof times) {
if (times < 1) {
JSUS.log('times must be greater or equal 1', 'ERR');
return;
}
times = ARRAY.rep([times], array.length);
}
result = [];
for (i = 0; i < array.length; i++) {
repeat = times[(i % times.length)];
for (j = 0; j < repeat ; j++) {
result.push(array[i]);
}
}
return result;
}; |
¶ ARRAY.arrayIntersectComputes the intersection between two arrays Arrays can contain both primitive types and objects. Params
a1
array
The first array
a2
array
The second array
Returns
array
All the values of the first array that are found
also in the second one
|
ARRAY.arrayIntersect = function(a1, a2) {
return a1.filter( function(i) {
return JSUS.in_array(i, a2);
});
};
|
¶ ARRAY.arrayDiffPerforms a diff between two arrays Arrays can contain both primitive types and objects. Params
a1
array
The first array
a2
array
The second array
Returns
array
All the values of the first array that are not
found in the second one
|
ARRAY.arrayDiff = function(a1, a2) {
return a1.filter( function(i) {
return !(JSUS.in_array(i, a2));
});
}; |
¶ ARRAY.shuffleShuffles the elements of the array using the Fischer algorithm The original array is not modified, and a copy is returned. Params
shuffle
array
The array to shuffle
Returns
array
copy The shuffled array
See
|
ARRAY.shuffle = function(array) {
var copy, len, j, tmp, i;
if (!array) return;
copy = Array.prototype.slice.call(array);
len = array.length-1; // ! -1
for (i = len; i > 0; i--) {
j = Math.floor(Math.random()*(i+1));
tmp = copy[j];
copy[j] = copy[i];
copy[i] = tmp;
}
return copy;
}; |
¶ ARRAY.getNRandomSelect N random elements from the array and returns them Params
array
array
The array from which extracts random elements
Returns
array
An new array with N elements randomly chosen
|
ARRAY.getNRandom = function(array, N) {
return ARRAY.shuffle(array).slice(0,N);
};
|
¶ ARRAY.distinctRemoves all duplicates entries from an array and returns a copy of it Does not modify original array. Comparison is done with Params
array
array
The array from which eliminates duplicates
Returns
array
out A copy of the array without duplicates
See
JSUS.equals
|
ARRAY.distinct = function(array) {
var out = [];
if (!array) return out;
ARRAY.each(array, function(e) {
if (!ARRAY.in_array(e, out)) {
out.push(e);
}
});
return out;
}; |
¶ ARRAY.transposeTransposes a given 2D array. The original array is not modified, and a new copy is returned. Params
array
array
The array to transpose
Returns
array
The Transposed Array
|
ARRAY.transpose = function(array) {
if (!array) return;
|
Calculate width and height |
var w, h, i, j, t = [];
w = array.length || 0;
h = (ARRAY.isArray(array[0])) ? array[0].length : 0;
if (w === 0 || h === 0) return t;
for ( i = 0; i < h; i++) {
t[i] = [];
for ( j = 0; j < w; j++) {
t[i][j] = array[j][i];
}
}
return t;
};
JSUS.extend(ARRAY);
})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
|