rangeCollection() Script
|
|
Input Vector: [A,B,C,D,E] --> (instance output out of many): ABC, BCD, CDE
|
This script can produce a great deal of different garnerings of the input array, accordingly to the values passed as its arguments. On the whole, its main feature is to break the array in an amount of subsets whose range matches the provided range argument, and in each of these generated ranges (for instance range=3) the input array entries are allocated either in a linear order (ABC, BCD...) or with a jumping order (ACE, BDF...), still depending upon the arguments values as you pass them. Your code first (then the Test Form and then the comments and instructions):
function rangeCollection(array, range, subsetJump, arrayJump, start, stark){
//returns array of arrays
//validate
if(!array||typeof(array)!="object"){return false}
for(var v=1;v<rangeCollection.arguments.length;v++){
if(isNaN(parseFloat(rangeCollection.arguments[v]))){return false}
rangeCollection.arguments[v]=parseFloat(rangeCollection.arguments[v])
if(rangeCollection.arguments[v]<0){return false}
}
range=(range)?range:1;
arrayJump=(arrayJump)?arrayJump:1;
start=(start)?start:0;
subsetJump=(subsetJump)?subsetJump:1;
//initialize
var L=array.length;
var output=new Array(0);
var insideJump=(subsetJump*(range-1));
//exceptions
if(range>L||
start>=L||
start+insideJump>=L||
subsetJump>=L){return false}
//run
while((start+insideJump)<L){
var subset=new Array(0)
for(var i=0, s=0;
i<range;
i++,s+=subsetJump){
subset[++subset.length-1]=(!stark)?array[start+s]:start+s;
}
output[++output.length-1]=subset
start+=arrayJump}
return output;/* keep this comment to reuse freely:
http://www.unitedscripters.com */}
There are several arguments which can be passed and whose purpose we discuss soon: what must be clear beforehand is that whenever an argument setting would determine, upon execution, an exceeding attempt to grab an array entry (namely an attempt to grab something which is out of the input array length bound) the script would stop in order to relinquish only those previous subsets whose elaboration was still in within the array length boundaries. Therefore you won't get partial subsets, but only those subsets in the input array whose positons allowed to build a match perfectly fitting your argument settings; unconsistent matches which might certainly have been produced allowing in attempts to build anyway what would have been possible to build with the input unelaborated remains, would not get produced at all.
Therefore, even all the validations performed, whenever detecting the impossibility to set up an output consistent with the given settings, would throw a false value as the script own return: if you're doubtuful on wether an input array vector may be arranged accordingly to your settings, always check first whether the returned output is an array object or a false boolean value. I reccomend you to always check first for a possible false value prior to whatever attempt to perform operations on an output array which might not be such at all.
Arguments:
- array is the input array and is mandatory.
- Given an array argument which is obviously mandatory, a range argument, whose default is 1, would allow you to arrange an output as follows:
given input vector ABCDEF
if range is 2 you get AB BC CD DE EF (no, you don't get F as an attempt to make FG if G is not there)
if range is 3 you get ABC BCD DEF (no, you don't get EF as an attempt to make EFG if G is not there)
if range is 4 you get ABCD BCDE CDEF (...)
I do believe you got it.
- If you set a start argument (and in case you do not set the in between arguments arrayJump and subsetJump which we discuss soon, then you have to pass both of them anyway as false or zero) the procedure outlined above will start using as starting point the array (vector) entry whose index positon corresponds to the specified start argument; therefore a range 2 and a start position of 3 on vector ABCDEF would yield:
DE EF
for letter D is what is at position 3 (of course keep in mind that counting of the objects positions in an array starts with zero, NOT with one). If you set no start, it defaults to zero (first entry).
- I believe settings above are fairly easy to understand. The problem may raise only when you try to grab what the arrayJump and subsetJump are for: they introduce two features:
arrayJump: each time a subset is collected, should next loop start with subsequent array (vector) entry or should it make a bigger leap? Example: given vector ABCDEF and range 2, default behaviour would be to produce:
AB BC CD DE EF
as you notice, after AB, the loop proceeds grabbing letter B to yield BC: if you want to override this linear sequence and instruct your script to grab not B but a letter whose postion is (jumps...) after X slots, set arrayJump=X; therefore some arrayJump=2 on the settings above would cause this:
AB CD EF
you may note that if the provided range value is equal to the arrayJump value, the produced output subsets are arranged as if they were reproducing the linear ranking of the input vector, although each subset is now arranged in an output entry of its own. Another instance my be: range = 3 arrayJump=3:
ABC DEF
Or, conversely and in order to introduce two different values, range=2 arrayJump=3 would yield:
AB DE
- As far as the subsetJump argument is concerned, it gets involved (and by the way defaults to 1) only once a range included in between start index value and arrayJump value exists (which tantamounts to all reasonable cases, actually, unless you are setting clearly inconsistent arguments such as subsets whose range is 8 chars on an input array which has only 4 entries), and determines the interval (leap) which must elapse between each entry of the subset: example: given usual input vector ABCDEF you may want to build subsets whose range is 3: without furhter instructions the script would porceed as follows and as you already know:
ABC BCD CDE DEF
but if you set a subsetJump of, say, 2, it would yield:
ACE BDF
you see: snippets whose range is 3 and whose distance between each collected char makes a leap of two:
ACE (between A and C: jump B, get SECOND; between C and E, jump D, grab SECOND from C)...
Or, say: an input ABCDEF with a range of TWO: usual defaults would be:
AB BC CD DE EF
with a subsetJump=2 would do as follows:
AC BD CE DF (stops here: an attempt to grab E and replicate the pattern to clutch a G and yield EG would fail since the input array bounds have been reached)
with a subsetJump=3 would do
AD BE CF
- stark argument: if set, returns the numeric indexes instead of the objects (to set it, being the last one, requires all previous arguments being set, at least as zero if you mean to pass them as false/null values).
A few possible invocations to give to you an idea:
- rangeCollection(array); //makes subsets of 1: actually, output is array itself
- rangeCollection(array, 3); //makes subsets of 3
- rangeCollection(array, 3, 0, 0, 4); //makes subsets of 3, starts from entry 4
- rangeCollection(array, 3, 0, 2); //makes subsets of 3, each subsets starts with a leap of 2 from previous subset starting entry char
- rangeCollection(array, 3, 2); //makes subsets of 3, in within each subset jumps by 2
- rangeCollection(array, 3, 4, 2, 4); //a complex cumulations of all the above!
- rangeCollection(array, 3,0,0,0,1); //makes subsets of 3 with stark set to return numerical indexes
linearRangeCollection() Script
|
|
Input Vector: [A,B,C,D,E] --> (instance output out of many): ABC, ACD, ADE, BCD, BCE, CDE
|
The following script is, to some extent (for it has been rearranged), a merge of the above one with the linearCollection() script that can be found in the other file whose topic are progressive matrix Collections (for the file click here): you may read explanations there for hints on how this script works. I mean that once (and provided) the workings fo that script are known, and the workings of the script above too, the following scripts features no special difficulties to be understood, so I won't comment it very much.
function linearRangeCollection(array, range, subsetJump, arrayJump, start, stark){
//returns array of arrays
//requires gen 4 browsers, using shift() built in method
//validate
if(!array||typeof(array)!="object"){return false}
for(var v=1;v<linearRangeCollection.arguments.length;v++){
if(isNaN(parseFloat(linearRangeCollection.arguments[v]))){ return false}
linearRangeCollection.arguments[v]= parseFloat(linearRangeCollection.arguments[v])
if(linearRangeCollection.arguments[v]<0){return false}
}
start=(start)?start:0;
range=(range)?range-1:0;/*RUN section -see it- already adds STILL as 1st entry, therefore range-1*/
if(range==0){
var foo=new Array(0)
for(var f=start;f<array.length;f++){/*make array of arrays consistent output*/
foo[++foo.length-1]=new Array(0)
foo[foo.length-1]=(!stark)?array[f]:f;
}
return foo}
arrayJump=(arrayJump)?arrayJump:1;
subsetJump=(subsetJump)?subsetJump:1;
//initialize
var L=array.length;
var output=new Array(0);
var insideJump=(subsetJump*(range-1));
//exceptions
if(range>L||
start-1>=L||
start+insideJump+arrayJump>=L||
subsetJump>=L){return false}
//RUN:
for(var i=start, still=i;
i<L;
i+=arrayJump){
if(i+insideJump<L){
var subset=new Array(0)
subset[++subset.length-1]=(!stark)?array[still]:still;
for(var x=0, s=i;
x<range;
x++,s+=subsetJump){
subset[++subset.length-1]=(!stark)?array[s]:s;
}
output[++output.length-1]=subset
}
if(i+arrayJump>=L){
still++;
i=still;
}
}
output.shift();/*deletes first entry*/
return output;/* keep this comment to reuse freely:
http://www.unitedscripters.com */}
Your probably need just a few words on its use: it makes progressions like the first script above, but this time they are recursively progressive, there fore if an input would be [ABCDEF] the first script would do, for instance:
ABC, BCD, CDE, DEF
But this would do:
ABC, ACD, ADE, AEF (see, subset starting with A)
BCD, BDE, BEF (see, subset starting with B)
ecc...
Therefore we have as many as 3 things here: - the leading letter (A, at first)
- and its (B) in the progression
- and then the subsetJump argument letter (maybe C is subsetJump=1).
The correspondences with the arguments are:
- Now, with the start argument you still determine at which level to start (A, or maybe D?). Remember arrays start being counted with number zero, not with number 1.
- With the arrayJump argument, you set the .
- With the subsetJump letter you will set as usual the subset jump amount (the third letter, and the fourth or fifth, according to the range argument)
- range argument as in function above.
Please note that the warnings for the rangeCollection() function applies here as well, namely that whenever the script detects it is impossible to yield an output of subset consistent with the arguments settings you have passed, it would return false.
So, for instance, you have input vector:
[ABCDEFGHI]
You set range=4 (that is, you want snippets of 4 chars)
you set start=2 (that is, you want to start not from the beginning but with letter C)
you set arrayJumpt=3 (that is, after C you want to grab a letter 3 slots far from C: would be G)
you set subsetJump=2 (that is, you want that each subsequent letter jumps by 2: would be , and now you got CGI and then a fourth letter to make the 4 chars long snippets: but is the limit of the input array, so the snippet of the prescribed length cannot be built up)
Accordingly, the script returns false.
One thing I want to stress is why I shift before returning (shifting means removing the first entry): it isn't that cool as a move, but what the script does is so nifty I really do not mind doing such a thing to remove just one (the unique actually) entry unconsistent with our purposes.
When the script loops to gather the array entries, it always starts with entry zero: but our loop would already include at each iteration the entry zero, including it by the agency of the variable named still, in the snippet:
subset[++subset.length-1]=array[]
Since still gets updated only when a whole loop of the array is completed in order to grant us the chance to match all with all (A[still] with BCDEF, then B[still] with CDEF, then C[still] with DEF...) and upon completion of each loop we reset still to still+1 and the value to still itself (you may really want to see how such resettings work in the linearCollection function [click here] file), therefore we would necessarily get at the very first iteration a double entry (sort of AA, if start argument=0, or CC if start argument= 2... by the way, start arguments default -obviously- to zero) for one of these matching entries is the one corresponding to and the other one the one corresponding to still when still equals A (when still is , that is). Now, I mean, either you set a conditional statement, or you to remove that. I believe a shift saves more time than a conditional statement inside a loop whose fatal destiny would be to match one and only one out of maybe one hundred iterations (anyway once out of the whole lot, for never again but once and ), and none the less would get checked each time if included as a conditional statement!
cubicRangeCollection() Script
|
|
Input Vector: [A,B,C,D,E] --> (instance output out of many): ABC, ABD, ABE, ACD, ACE, ADE, BCD, BCE, BDE, CDE Does not produce all the combinations, though: if you want ALL the combinations, use the fullRangeCollection script
|
This script will take avail of linearRangeCollection and upon each entry of it would append all the subsequent entries of the input array: it is just a more comprehensive output than the 2 range collections featured above and you can immediately understand the differencies by simpy running the scripts on each form with the default settings and compare the outputs: they are to be self evident if you just slightly scan them at first sight. Doesn't require many specifications since all the job is performed by the previous linearRangeCollection: it is passed with stark as 1 so to grab only the indexes and take avail of them to detect the next entry to append. Anyway, you can pass to this functiona stark argument of its own, and if set to one, would return the indexes and not the actual entries.
function cubicRangeCollection(array, range, subsetJump, arrayJump, start, stark){
//REQUIRES: linearRangeCollection()
//returns array of arrays
//returns false if settings are unconsistent with the input array
//requires gen 4 browsers, using concat() built in method
array=(array)?array:0;
range=(range)?range:0;
subsetJump=(subsetJump)?subsetJump:1;
arrayJump=(arrayJump)?arrayJump:0;
start=(start)?start:0;
var input=linearRangeCollection(array, range, subsetJump, arrayJump, start, (range<=2)?stark:1);
if(range<=2){return input};
if(!input){return false};
var output=new Array(0);
for(var i=0;i<input.length;i++){
for(var e=input[i][input[i].length-1];e<array.length;e+=subsetJump){/*note: e+=subsetjump*/
var temp=input[i].slice(0,input[i].length-1);
if(!stark){
for(var t=0;t<temp.length;t++){
temp[t]=array[temp[t]];
}
}
temp[++temp.length-1]=(!stark)?array[e]:e;
output[++output.length-1]=temp
}
}
return output;/* keep this comment to reuse freely:
http://www.unitedscripters.com */}
fullRangeCollection() Script
|
|
If you just want all the combinations within a given range, this one is your script
|
This script posed at first unbelievable and deeply frustratring difficulties (in spite of all those guys on the net that, having no cognizant clue and borrowing scripts without ever dealing with the actual, real problem themselves, would call this "such simple a task"): in fact, when attempting to draw all the combinations within a given range, most of the approaches I attempted (and I think every approach which pursue this goal would eventually end on this very same shore) always went through phases where all previous combinations whose length was inferior to the given range were assembled: it just appears unescapable.
At first I was considering it disfunctional, for if I have to go through building all the ranges inferior to the given range before attaining it, then I could see no difference from the fullCollection script featured at bottom of this page: what was the difference?
In fact, there was basically none, except that the range must be set as the output limit instead of setting as limit the input array length itself. So, with some minor changes to take into account the range factor, here is your full range collection subroutine, and for its details you'd see the documentation (complete and reasonably clear, I hope) for the fullCollection script which can be found clicking one of the two links above (or: this).
This script saves all the features of that one, namely it's comparatively fast (relatively to the task): given the high complexity of the task, it's probably one of the fastest available out there, although the fullCollection not ranged script is still faster (on a Pentium III produces 32,000 entries in 19 seconds). To invoke this function, you just have to pass the first two arguments: an input array and a range limit: other arguments are entirely optional and default to the most obvious values (starting from zero, increasing by one, you see!).
If some arguments exceed the input vector limits, this subroutine returns an empty array (output.length=0) instead of false like the previous subroutines featured on this file: the only reason for this is that we have to perform a wider validation set (more returns upon exceptions, that is): I felt like I would have been nagging you if I were to return false in any circumstance always assuming that if some arguments are unconsistent, then you do not want any type of output at all (return false): there were some cases where you arguably wish the input array being returned: therefore I arranged in order to exhibit some consistence with this type of instances, so I shaped also all the returns for the exceptions as returns of an array, but without length: if your subroutine returns an array with no length, you know there was something wrong in the inputs.
function fullRangeCollection(array, range, start, stark){
/*requires gen 4 browsers using concat() built in methods*/
//returns array of arrays
//exceptions:
if(!array|| !array.length|| typeof(array)!="object"){return new Array(0)};
if(range){range=parseInt(range)};
if(!range||isNaN(range)||range<=1){return (start)?array.slice(start):array};
if(array.length<range){return new Array(0)};
//initialize:
start=(start)?parseFloat(start):0;
if(start>array.length|| start+range>array.length){return new Array(0)};
var output=new Array(0);
var builder=new Array(0);//do not use []
//populate:
for(var p=start;p<array.length;p++){
var B=++builder.length-1;
builder[B]=new Array(0);
builder[B][++builder[B].length-1]=p;
}
//run:
while(builder[builder.length-1].length!=range){
var resetBuilder=new Array(0);
for(var i=0;i<builder.length;i++){
for(var x=builder[i][builder[i].length-1]+1; x<array.length; x++){
var L=++resetBuilder.length-1;
resetBuilder[L]=new Array(0);
resetBuilder[L]=resetBuilder[L].concat(builder[i]);
resetBuilder[L][++resetBuilder[L].length-1]=x;
}
}
builder=resetBuilder;
}
output=builder;builder=null;
//streamline:
if(!stark){//assign letters
for(var e=0;e<output.length;e++){
for(var f=0;f<output[e].length;f++){
output[e][f]=array[output[e][f]];
}
}
}
return output;/* keep this comment to reuse freely:
http://www.unitedscripters.com */}
|