Recursion Issue(I just can't understand what it is doing) - javascript

I have been reading multiple articles and as soon as I go to do something recursively I just don't get it, I understand the base case, but I don't get the recursive step. so I have this code which is a solution I found.
function range (start, end) {
if (end < start) return [];
if(start == end) {
return [start];
}
else {
const numbers = range(start , end - 1);
numbers.push(end)
return numbers;
}
}
so, I understand the start == end, here is what I do not get.
why is numbers an array? I don't see anywhere that range is an array, I also don't understand if I use start + 1 and push start, the numbers are backward. I have spent 3 weeks so far trying to get a better grasp on recursion and just can not do it, if someone could please help explain to me and maybe offer some resources I have not found? I watched Al Sweigarts recursion video, and thought I understood it until I went to do something, I found it its the recursive step that is just destroying me, I am trying everything I can to understand and get an idea of how this works but I am just super frustrated with myself at this point. thank you for any help.

The only possible thing range is returning here is [] which is an array and [start] which is also an array. So when youre calling range recursively from the else block then you'll always end up with an array since there arent any other paths the code can go.

See comments inline:
function range (start, end) {
console.log("range function is running with arguments of: ", start, end);
// If end < start, exit function and return an empty array
if (end < start) return [];
// If not, check if start and end are equal (with conversion)
if(start == end) {
// If so, return an array that only contains the start parameter value and exit
return [start];
} else {
// If the above tests are false, call the function again
// but with end being one less than before and assign either
// array from above as the value of numbers.
const numbers = range(start , end - 1);
numbers.push(end); // Add end to the end of the array
return numbers; // Return this array instead of the other 2
}
}
console.log("Final array is: ",range(10,20)); // Display the final returned array

domain and codomain
A function's inputs are known as its domain and the function's return type is known as its codomain. These types can effectively guide us when writing our implementation -
range : (number, number) -> number array
fill in the blanks
This helpful template can get you started on almost any recursive function. It may seem challenging at first, but things become easier as we fill in the pieces. According to the types for range, we already know 2 and 3 must return some array -
// range : (number, number) -> number array
function range(start, end) {
if (...) // 1
return ... // 2 (must return array)
else
return ... // 3 (must return array)
}
1. base case
Each recursive function needs a base case, which does not result in a recursive call, allowing the function to eventually exit. Under what conditions does the range function exit?
// range : (number, number) -> number array
function range(start, end) {
if (end < start) // 1 ✅ when end subceeds start, exit
return ... // 2
else
return ... // 3
}
2. base value
When the exit condition is met, we need to return the base value. Typically it is the empty value of our function's return type, or codomain. Since we must return an array, what is the empty value for arrays?
// range : (number, number) -> number array
function range(start, end) {
if (end < start) // 1 ✅
return [] // 2 ✅ an empty array is []
else
return ...
}
3. inductive case(s)
We must specify what happens when the exit condition is not met in the else branch, known as the inductive cases. If end < start is not true, by induction we know that end >= start. In this case we solve the problem for the current start and end, and append it to the result of the smaller sub-problem. In other words, if I have range(P,Q) the answer is -
append Q to the result of range(P, Q - 1)
Remember the type for range gives us a hint. When range is called with new arguments, the first and second arguments are both number. The return value will be an array of numbers, or number array.
In JavaScript we write that as -
// range : (number, number) -> number array
function range(start, end) {
if (end < start) // 1 ✅
return [] // 2 ✅
else
return [...range(start, end - 1), end] // 3 ✅ minus and append
}
substitution model
Recursion is a functional heritage and so using it with functional style yields the best results. This means writing functions with referential transparency, meaning there are no observable side-effects and the function will always return the same value when the same inputs are used. Using the substitution model we can substitute any function call for its return value -
range(3,6)
[...range(3, 6 - 1), 6]
[...range(3, 5), 6]
[...[...range(3, 5 - 1), 5], 6]
[...[...range(3, 4), 5], 6]
[...[...[...range(3, 4 - 1), 4], 5], 6]
[...[...[...range(3, 3), 4], 5], 6]
[...[...[...[...range(3, 3 - 1), 3], 4], 5], 6]
[...[...[...[...range(3, 2), 3], 4], 5], 6]
[...[...[...[...[], 3], 4], 5], 6] // base case
[...[...[...[3], 4], 5], 6]
[...[...[3, 4], 5], 6]
[...[3, 4, 5], 6]
[3, 4, 5, 6]
using plus instead of minus
It should be helpful for us to see that we can solve range using + and prepend instead of - and append -
// range : (number, number) -> number array
function range(start, end) {
if (start > end) // ✅ when start exceeds end, exit
return []
else
return [start, ...range(start + 1, end)] // ✅ plus and prepend
}
range(3,6)
[3, ...range(3 + 1, 6)]
[3, ...range(4, 6)]
[3, ...[4, ...range(4 + 1, 6)]]
[3, ...[4, ...range(5, 6)]]
[3, ...[4, ...[5, ...range(5 + 1, 6)]]]
[3, ...[4, ...[5, ...range(6, 6)]]]
[3, ...[4, ...[5, ...[6, ...range(6 + 1, 6)]]]]
[3, ...[4, ...[5, ...[6, ...range(7, 6)]]]]
[3, ...[4, ...[5, ...[6, ...[]]]]] // base case
[3, ...[4, ...[5, ...[6]]]]
[3, ...[4, ...[5, 6]]]
[3, ...[4, 5, 6]]
[3, 4, 5, 6]
demo
function rangeplus(start, end) {
if (start > end)
return []
else
return [start, ...rangeplus(start + 1, end)]
}
function rangeminus(start, end) {
if (end < start)
return []
else
return [...rangeminus(start, end - 1), end]
}
console.log(rangeplus(3,6))
// [3, 4, 5, 6]
console.log(rangeminus(3,6))
// [3, 4, 5, 6]

You cannot understand a recursive algorithm ( not your own ) by reading its lines only.. so, you need to apply a simple example to get the right result and understand where it's goes to, this is my example :
First call
start = 1
end = 0
=>start > start
Algorithm result : return []; ===> an empty array
First call
start = 1
end = 1
=> start = end
Algorithm result : return [start]; ===> array of ONE element (start value)
First call
start = 1
end = 5
=> start < end
in this case the algorithm will call itself const numbers = range(start , end - 1); by changing the end value and storing it in array called numbers
Second call :
numbers = []
range(1,5-1)
(don't forget, "end" (4) is still greater than "start" so it will go to the recall iteration )
Third call :
numbers []
range(1,4-1)
=>"end" is still greater (3)
Fourth call :
numbers []
range(1,3-1)
=>"end" is still greater (2)
Fifth call :
numbers []
range(1,2-1)
=>now, "end"(1) is equals to "start" (1),the next iteration will act differently
Sixth call :
start = end ==> this call will return start value (1) and push it to the constant number
so, now, the algorithm will continue the execution of not executed lines after the previous calls (I mean numbers push() ):
Result of sixth call = 1
it will push it to numbers, and return numbers (array of one element [1])
Result of fifth call = 2
push to numbers ==> numbers is [1,2]
etc. Until it reaches the first call.
Final Result : [1,2,3,4,5]
I hope that it can help.

Related

How does the outer variable in this recursive program not getting reset each time

Below is the program to find the shortest combination to achieve the target sum from a given list of array.
For e.g,
Target sum is 5,
and list of array is [2, 3, 5]
So possible output is [2, 3] and [5] out of which [5] being the shortest is the answer.
Now here's my query:
As per my interpretation shortestCombination gets reset to null on each recursive calls, i.e bestSum(5, numbers), bestSum(3, numbers), bestSum(1, numbers) etc. But how does it magically equate to being [3] and then [3, 2] (instead of null) and finally gets replaced with [5]?
const bestSum = (targetSum, numbers)=>{
if(targetSum === 0) return [];
if(targetSum < 0) return null;
let shortestCombination = null;
for(let num of numbers){
const remainder = targetSum - num;
const remainderCombination = bestSum(remainder, numbers);
if(remainderCombination !== null){
const combination = [...remainderCombination, num];
if(shortestCombination === null || combination.length < shortestCombination.length){
shortestCombination = combination;
}
}
}
return shortestCombination
}
console.log(bestSum(5, [2, 3, 5]))
Let's look at a trivial example: bestSum(4, [4]).
The first call sets shortestCombination = null, then enters a loop. The loop only iterates the once, and sets remainder = 4-4 = 0. Then it calls bestSum(0, [4]).
This second call sees that targetSum == 0 and returns [].
Back in the first call, remainderCombination = []. It builds combination = [...[], 4] = [4]. Then it checks whether shortestCombination is null or short than combination. It is null, so it sets shortestCombination = [4]. Then the loop ends and the function returns [4].
If that makes sense, then apply it to the next less trivial input: bestSum(2, [1]).
The first call sets its shortestCombination = null, calls bestSum(1, [1]).
The second call sets its shortestCombination = null, calls bestSum(0, [1]).
This third call returns [].
The second call sets combination = [1], compares this to its shortestCombination (which is null) and sets shortestCombination = [1], returning [1].
The first call sets combination = [1,1], compares this to shortestCombination (which is null) and sets shortestCombination = [1,1], returning [1,1].
So, yes, each recursive call has its its own shortestCombination; there is no magic.
Elaborating further on the premise Welbong has set:
Let's run the program for bestSum(2, [1, 2])
The loops would run two times for each of 1 and 2.
Now let's see what happens when it runs for 1.
bestSum(1, [1, 2]) is called and put on to the stack which again would run for two times, for num, 1 and 2.
Now running for 1, bestSum(0, [1, 2]) will be called which returns an empty array and combination gets set to [...[], 1] or, [1]
Now it again runs for 2, bestSum(-1, [1, 2]) but this times it returns null and hence doesn't change the values of combination and shortestCombination.
So the result of bestSum(1, [1, 2]) turns out to be [1].
This stack is popped out and now we have bestSum(2, [1, 2]) and for num 1, it has returned [1, num] i.e [1, 1]
Now bestSum(2, [1, 2]) runs for 2
it enters the loop, in turn calls bestSum(0, [1, 2]). This again would have run twice for each of the run, however, it returns [] in the beginning itself. So, we have combination as [2] and shortestCombination as [2] again.
So now it's time for the final stack to be popped out bestSum(2, [1, 2]) currently it stores [1, 1] that was the result of iteration through num 1, in the second iteration for 2, we have [2] and this being the shortest replaces [1, 1] and finally [2] is returned.
So as it turns out, each recursive call gives the shortestCombination that is the shortest array resulting from running bestSum(targetSum, nums) for each of the nums. Each results serve to the stack below it and finally the first stack popps out which is the result of shortest of the bestSum(targetSum, nums) running for each of nums.

Javascript recursion related question about push() and unshift() methods working opposite

function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = countup(n - 1);
countArray.push(n);
return countArray;
}
}
console.log(countup(5));
After running the above code it returns an array: [1, 2, 3, 4, 5], but push() adds new values at the end of an array so when value of n was 5 it should push 5 to the end of the array and when value of n got 4 it should push 4 at the end of the array like [5,4].
So why not it is returning [5,4,3,2,1] ? It is hard to understand what is happening in this code probably because of this recursion. Isn’t unshift() (which add new values to start of the array) should return [1,2,3,4,5] and push() [5,4,3,2,1] why opposite is happening?
As #Joseph stated in a comment the second to last function call would get pushed to the array first, then it would return that array, where it immediately adds the next number up the call stack.
Here are the steps being taken.
Initial call enters itself recursively n times, where the bottom call returns [] and then [1], [1, 2] ... [1, 2, ..., n] all the way up the call stack where upon the first function call ends and the program does something else.
To get [n, ..., 2, 1] you need to use the Array.prototype.unshift() method, which takes any javascript primitive type, ie String, Number, Boolean, and Symbols, in a comma separated format, like countArray.unshift(4, 5) or countArray.unshift(...anotherArray), and adds them to the beginning of the array.
ie
let someArr = [3, 2, 1];
someArr.unshift(5, 4);
console.log(JSON.stringify(someArr));
// outputs [5, 4, 3, 2, 1]
or
let someArr = [1, 2, 3];
let anotherArr = [5, 4]
someArr.unshift(...anotherArr);
console.log(someArr);
// outputs [5, 4, 1, 2, 3]
Where the output of
function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = countup(n - 1);
countArray.unshift(n);
return countArray;
}
}
console.log(countup(5));
will be [5, 4, 3, 2, 1] tested with node in Vscode.
One useful way to think about this is to start by imagining you already had a function that does what you want for lower values, and then see how you would write one that works for higher values. That imaginary function should be a black box. All we should know is that it does what we want in the case of lower values. We don't care about its implementation details.
So lets say we had a function imaginaryBlackBox, and we knew that it returned the correct countUp values that we want. So, for instance, we know that imaginaryBlackBox (4) returns [1, 2, 3, 4].
Now, knowing that, how might we write a function that works for an input of 5 as well? How about something like this:
function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = imaginaryBlackBox(n - 1);
countArray.push(n);
return countArray;
}
}
Again, we don't know how imaginaryBlackBox works. We just know that it returns the correct result for lower values of n. Our base case remains obvious. For another case, some n greater than 0, we call imaginaryBlackBox(n - 1), and by our basic assumption, we know that will return [1, 2, 3, ..., (n - 1)], which we store in countArray. Then we push n onto that array, to end up with [1, 2, 3, ..., (n - 1), n]. We return that value and we're done.
Now here's the trick. We know an implementation of imaginaryBlackBox -- it's the function we're writing! So we can simply replace it with countUp and know it will work.
function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = countUp(n - 1);
countArray.push(n);
return countArray;
}
}
This required a few assumptions, and they are important to all recursive functions:
There is at least one base case whose value we can calculate without any recursive call. Here, when n is < 1, we simply return [].
For other cases, we can break down our problem into one or more recursive cases, where the input is in some clear and measurable way closer to a base case, so that subsequent steps will hit a base case in a finite number of calls. Here we reduce n by 1 on every step, so eventually it will be below 1.
Our function is effectively pure: its outputs depend only on its inputs. That means we can't count on changing a global variable or reading from one that might be changed elsewhere. Note that I use the qualifier "effectively" here; it doesn't matter if this function has observable side-effects such as logging to the console, so long as its output is dependent only on its input.
Anytime you have those conditions, you have the makings of a good recursive function.

Refactor from Procedural Paradigm to Functional Paradigm

In the process of learning functional programming, I am trying to refactor the following code using map, filter, and/or reduce.
I see that I can deal with the conditional using the filter method, but don't know how to handle the repeated assignment so I can avoid use of a for loop.
I am thinking that I would use the map method to handle the diff assignments, and chain a filter method that would deal with the conditional. Am I on the right track?
Would someone be kind enough to refactor the following code in the functional paradigm and explain. Thanks.
This function finds the first non-consecutive number in an array.
function firstNonConsecutive (arr) {
var diff = 0;
for(var i = 0; i < arr.length; i++) {
diff = arr[i+1] - arr[i];
if(diff > 1) {
return arr[i+1];
}
}
return null;
Consider using Array.find https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find, like most functional array functions it takes a callback/predicate that takes 3 parameters, the item, the index and the whole array. With this you can look ahead/behind in the same way you currently do. Like this:
function firstNonConsecutive2(arr) {
return arr.find((item, index, array) => {
const diff = array[index - 1] - item; // Use index -1 to look behind instead of ahead since we want to return/find the item that is non-consecutive
return diff === 0; // I think this was a small bug in your version which worked if the numbers were incrementing only
});
}
In the first iteration of the find "loop" it'll try to diff undefined with for example 1, which is NaN, NaN is not equal to 0 so it keeps searching. Next it'll try maybe 1 and 2 so diff becomes -1 so it keeps searching. Until it reaches for example 5 and 5, which diffs to 0 so the find predicate is now true, so it will return the second 5 since that is the current item, we're looking behind us by using index - 1.
Let me know if you want further explanation of something!
If you are looking into fp, then also recursion would find a good application here:
const firstNonConsecutive = (list) => {
if (!list.length) {
// list is empty, not found
return -1;
}
const [head, ...tail] = list;
const [n] = tail;
if (n - 1 !== head) {
// found
return n;
}
// yet another round
return firstNonConsecutive(tail);
};
console.log(
firstNonConsecutive([1, 2, 3, 4, 5, 6, 7, 9, 10]),
);
https://en.wikipedia.org/wiki/Recursion_(computer_science)
You want to use Array.find, not .map, .filter, or .reduce. You could find a way to use those, but they waste time because they don't return as soon as the first match is found.
Here are some progressively more verbose solutions to help you understand how the first one works.
The second is the most functional, because it's declarative unlike the first.
array.find(nonConsecutive) reads close to plain English and declares what you want to do, leaving the imperative implementation details hidden away inside the nonConsecutive function.
const array = [1, 2, 3, 4, 5, 6, 7, 9, 10];
console.log(
array.find((n, i) => i && n != array[i - 1] + 1) // 9
);
const nonConsecutive = (n, i, arr) => i && n != arr[i - 1] + 1;
console.log(
array.find(nonConsecutive) // 9
);
console.log(
array.find(function (number, index) { // we don't need third "array" argument because the array is already in scope.
if (index == 0) return false; // if index is zero, return. Otherwise, next line would access index -1.
if (number != array[index - 1] + 1) return true; // if number is not equal to the the previous number, plus one, it's not consecutive. Return it.
return false; // if we reach this line than the number must be consecutive, so return false.
}) // 9
);
Recursion by mathematical induction -
If the first element, a, or the second element, b, are null, return undefined
(induction) Neither the first element, a, nor the second element, b are null. If b is consecutive to a, return the recursive result of the smaller problem
(induction) Neither the first element, a, nor the second element, b, are null and b is not consecutive to a. Return the answer, b.
const firstNonConsecutive = ([ a, b, ...more ]) =>
a == null || b == null
? undefined // 1
: b === a + 1
? firstNonConsecutive([ b, ...more ]) // 2
: b // 3
console.log(firstNonConsecutive([ 4, 5, 6, 8, 9, 10 ]))
// 8
console.log(firstNonConsecutive([ 7, 8, 9, 10, 13, 14 ]))
// 13
console.log(firstNonConsecutive([ 99 ]))
// undefined
console.log(firstNonConsecutive([]))
// undefined

Interval range insert with split into unique ranges

Looking for algorithm ideas how to insert into interval range value so it won't overlap existing intervals.
Interval range is sorted smallest to larger [[0, 1], [3, 5]].
Now inserting interval range [0, 7] to [[0, 1], [3, 5]] -> [[0, 1], [1, 3], [3, 5], [5, 7]] -> generated two new ranges other remain same.
Here is another example, inserting range [-3, 5] to [[0, 1], [6,7]] -> [[-3, 0], [0, 1], [1, 5], [6, 7]]
All programming languages(especially JavaScript) are welcomed also pseudocode implementations.
in the actual code there is a differentiation between old interval ranges and new ranges after applying certain operation those ranges would be merged together. I wanted to split the question into smaller chunk so the merging part is left out.
Solely: It is easier to merge in the new interval directly, instead of artificially splitting it up. So this is what I propose below (C++):
using DataType = /* whatever appropriate; double, int, unsigned int, ...*/;
using Interval = std::pair<DataType, DataType>;
std::vector<Interval> intervals;
void insert(Interval x)
{
if(intervals.empty() || x.second < intervals.front().first)
{
intervals.insert(intervals.begin(), x); // (1)
}
else if(x.first > intervals.back().second)
{
intervals.push_back(x); // (2)
}
else
{
auto b = intervals.begin();
while(b->second < x.first)
{
std::advance(b, 1);
}
// cannot be END iterator, otherwise would have been caught by (2)
if(x.second < b->first)
{
// this is a new interval in between std::prev(b) and (b)
intervals.insert(b, x);
}
else
{
// b is overlapping with x!
if(b->first > x.first)
{
b->first = x.first;
}
auto e = std::next(b);
while(e != intervals.end() && e->first <= x.second)
{
std::advance(e, 1);
}
// e is the first interval NOT overlapping with x!
auto l = std::prev(e);
b->second = std::max(x.second, l->second);
// drop all subsequent intervals now contained in b (possibly none)
intervals.erase(std::next(b), e);
}
}
}
Algorithm only, spared the design efforts of packing into class, having convenience function accepting begin/end markers (instead of interval), ...
If the data type you intend to use does not provide a back accessor (C++: e. g. std::forward_list): No problem, just drop the second if (containing (2)); then, however, b can be the end iterator, so you'd have to test for and if the test succeeds, you can insert at end. You'd most likely not have an 'insert before' then, so you'd need to track b's and later e's predecessors separately, too...

group items in array in javascript

I have an array of items, can be objects with many properties, and I want to group some of these items based on order:
example:
[a,b,c,d,e] => [a,[b,c,d],e]
must group (b, c, d) or (a) or (b, c) or (all)
must not group (a, c) or (a, d) for example because they are not sequential
Some possibilites:
[a,b,c,d] to [[a,b,c,d]]
[a,b,c,d] to [[a],b,c,d]
[a,b,c,d] to [[a,b],c,d]
[a,b,c,d] to [[a,b,c],d]
[a,b,c,d] to [a,b,[c,d]]
always sequential items
think of item a like an object with index;
If I understand correctly, you want to group n sequential elements of the array starting from an index ind and put that that group back into the array at the same index. You can acheive that using splice:
function group(arr, ind, n) {
var g = arr.splice(ind, n); // cut out n elements from the array at index ind
arr.splice(ind, 0, g); // push back those cut-out elements into the same index ind (the elements are in array because of the first slpice call)
}
var arr = [1, 2, 3, 4, 5, 6];
group(arr, 2, 3);
console.log(arr); // [1, 2, [3, 4, 5], 6]
EDIT:
As requested, changing group to create a new array instead of altering the original and taking start and end indexes. So for that we are going to use slice/concat instead of splice:
function group(arr, start, end) {
return [].concat(arr.slice(0, start), [arr.slice(start, end + 1)], arr.slice(end + 1));
}
var arr = [1, 2, 3, 4, 5, 6];
console.log(group(arr, 2, 3)); // => [1, 2, [3, 4, 5], 6]
console.log(group(arr, 4, 6)); // => [1, 2, 3, 4, [5, 6]]
console.log(group(arr, 0, 3)); // => [[1, 2, 3, 4], 5, 6]
which concatinate the subarrays: from 0 to start, from start to end + 1 (put in an array of its own so its stays grouped) and from end + 1 onward. If you want the end index to be exclusive (the element at end not included) then just change end + 1 to end.
Based on the more recent comments you may be looking for Array's own, built-in slice method, it provides a continuous sub-region of an array, where start and end positions are its arguments:
function format(a){return "["+a.join(",")+"]";}
var arr=['a','b','c','d','e'];
console.log("original: "+format(arr));
console.log("slice(0,1): "+format(arr.slice(0,1)));
console.log("slice(0,2): "+format(arr.slice(0,2)));
console.log("slice(1,4): "+format(arr.slice(1,4)));
console.log("slice(2,4): "+format(arr.slice(2,4)));
console.log("slice(2,2): "+format(arr.slice(2,2)));
Note 1: The second argument is the position of the "last+1" element you want, it is best seen in the last example where slice(2,2) provides an empty array
Note 2: format is just about getting array contents in one line, console.log(somearray) displays the elements vertically.
Then of course you can do whatever you need, but it is definitely worth to note that this function exists and it is built-in.
Like building the array-in-array thing you describe:
function format(a){var s="[",first=true;a.forEach(function(i){
if(first)first=false;else s+=",";s+=i instanceof Array?format(i):i;});
s+="]";return s;}
function group(arr,begin,end){
var ret=[];
for(var i=0;i<begin;i++)ret.push(arr[i]);
ret.push(arr.slice(begin,end));
for(var i=end;i<arr.length;i++)ret.push(arr[i]);
return ret;
}
var arr=['a','b','c','d','e'];
console.log("original: "+format(arr));
console.log("group(arr,0,1): "+format(group(arr,0,1)));
console.log("group(arr,0,2): "+format(group(arr,0,2)));
console.log("group(arr,1,4): "+format(group(arr,1,4)));
console.log("group(arr,2,4): "+format(group(arr,2,4)));
console.log("group(arr,2,2): "+format(group(arr,2,2)));
Examples are the same as for the slice-explanation, including the empty array in the last one (with 2,2). It is up to you if you want such empty element (as kind of a 'cursor') or not.
And of course the thing also works with the nested loops in my original answer, if you want to generate all possible selections from an array - that is how your question initially seemed to me:
function format(a){var s="[",first=true;a.forEach(function(i){
if(first)first=false;else s+=",";s+=i instanceof Array?format(i):i;});
s+="]";return s;}
function group(arr,begin,end){
var ret=[];
for(var i=0;i<begin;i++)ret.push(arr[i]);
ret.push(arr.slice(begin,end));
for(var i=end;i<arr.length;i++)ret.push(arr[i]);
return ret;
}
var arr=['a','b','c','d','e'];
console.log("original: "+format(arr));
for(var i=0;i<arr.length;i++)
for(var j=i+1;j<=arr.length;j++){
console.log(format(group(arr,i,j)));
}

Categories

Resources