implementing a recursive reverse function in javascript - javascript

I'm trying to write a function that reverses a list. The function is recursive.
I know javascript does not have TCO, but i wanted to experiment with this anyway:
reverse = function(list) {
if (list.length < 2) { return list }
fk = fork(list);
return reverse(fk.tail).concat([fk.head])
}
the fork function splits a list to a head and a tail:
fork = function(list) {return {head: list[0], tail: list.slice(1)}}
When I call reverse() with the list [1,2,3,4,5], I get this result:
reverse([1,2,3,4,5]) // [5,4,4,4,4]
Not sure what I'm doing wrong here. The expected result is [5,4,3,2,1].
Please help.

You should lint your code, that'll help you tremendously. In particular, this code fails because fk is treated as a global variable. If you prefix it with var, it works:
var reverse = function(list) {
if (list.length < 2) { return list }
var fk = fork(list);
return reverse(fk.tail).concat([fk.head])
}
As it stands now, at each recursive call you modify the same fk variable, essentially meaning concating the same fk.head - the element before the last one.
In fact, you don't even need temporary variable here:
function recursive_reverse(list) {
return list.length < 2 ? list : recursive_reverse(list.slice(1)).concat([list[0]]);
}
As for tail recursion, here's one possible approach:
function recursive_reverse(list) {
return tail_recursive_reverse(list, []);
}
function tail_recursive_reverse(list, res) {
if (!list.length) return res;
var head = list[0];
var tail = list.slice(1);
res.unshift(head);
return tail_recursive_reverse(tail, res);
}

Related

Is there an intuitive way to understand how this Javascript callback function is working?

Code line in question:
callbackFn ? callbackFn(currentNode) : levelOrderList.push(currentNode.value);
I am having trouble of a way to think of this in psuedo-code terms since 'callbackFn' is used like a function but not defined like a function.
I know this code works and have ran it myself. I have also solved this without using the callbackFn, but I would really like to understand why this works.
My guess for psuedo cod would be:
if callbackFn exists (not null or undefined), then return callbackFn(currentNode).
else push currentNode.value to the levelOrderList.
Full code for context:
function levelOrder(callbackFn) {
const queue = [this.root];
const levelOrderList = [];
while (queue.length > 0) {
const currentNode = queue.shift();
callbackFn ? callbackFn(currentNode) : levelOrderList.push(currentNode.value);
const enqueueList = [
currentNode?.leftChild,
currentNode?.rightChild
].filter((value) => value);
queue.push(...enqueueList);
}
if (levelOrderList.length > 0) return levelOrderList;
}
Your guess for pseudo code is correct.
The author of that could should better have used an if...else structure like your pseudo code does. The conditional operator (? :) is used here as an unnecessary short-cut. Normally you would use the conditional operator to use the value that it evaluates to, like x = condition ? a : b;. But here that value is ignored. There is really no good reason to avoid if...else here.
The author added support for a callback mechanism as an alternative to returning an array. This doesn't look like best practice to me either. For two reasons:
This "polymorphism" can be confusing for the user of such an API. It is easier to understand when the two functionalities are offered by two different functions, one that returns the result in an array, another that calls the callback. The caller will choose the function based on how they want to deal with the traversed nodes.
A callback mechanism is rather "old style". It makes more sense to turn this function into a generator function. The caller can then easily decide what to do with the nodes that the returned iterator yields: collect those nodes in an array or just process them one by one.
This is how that generator function would look like:
class Node {
constructor(value) {
this.value = value;
this.leftChild = this.rightChild = null;
}
}
class Tree {
constructor(...values) {
this.root = null;
for (let value of values) this.add(value);
}
add(value) {
function addTo(node) {
if (!node) return new Node(value);
if (value < node.value) {
node.leftChild = addTo(node.leftChild);
} else {
node.rightChild = addTo(node.rightChild);
}
return node;
}
this.root = addTo(this.root);
}
*levelOrder() {
if (!this.root) return;
const queue = [this.root];
while (queue.length > 0) {
const currentNode = queue.shift();
yield currentNode.value;
if (currentNode.leftChild) queue.push(currentNode.leftChild);
if (currentNode.rightChild) queue.push(currentNode.rightChild);
}
}
}
// Demo
const tree = new Tree(4, 6, 7, 2, 1, 5, 3);
// Several ways to use the levelOrder generator function:
console.log(...tree.levelOrder());
console.log(Array.from(tree.levelOrder()));
for (let value of tree.levelOrder()) console.log(value);

Chained array creator

Just for fun, I'm looking for a way to create a function, array, with the following behavior:
array() // []
array(2) // ugly function thing
array(2)() // [2]
array(2)(3)() // [2,3] etc
The closest I can come is
function array(x) {
if (x == null)
return []
return function() {
// same as above?!
// I don't want some inelegant solution involving a lot of additional parameters
}
}
Is there a way to do this in ECMA5? If not, prove that the syntax can't accomodate such a function.
Yes, "same as above". This is solved by a "recursive"1 call:
function makeArrayAppender(arr) {
return function array() {
var args = Array.prototype.slice.call(arguments);
if (!args.length)
return arr;
else
return makeArrayAppender(arr.concat(args));
};
}
var array = makeArrayAppender([]);
1: As the function is called from the returned "thunk" function, not from the call itself, it's not really recursive. It's more like a tail-call-optimised function, being invoked manually in-a-row without filling the stack
I think this should do exactly what you are looking for. The self-executing function scopes off r and rr, which are basically static variables using this implementation. Of course, you need to reset r after assigning it to rr, so you can return the Array when ra has an undefined argument, which then stops the recursive behavior.
var array = (function(){
var r = [], rr;
function ra(a){
if(a === undefined){
rr = r; r = []
return rr;
}
else{
r.push(a);
return ra;
}
}
return ra;
})();
console.log(array()); console.log(array(5)()); console.log(array());
console.log(array(7)(2)());

List data structures in JavaScript

In an exercise in the book Eloquent JavaScript I need to create a list data structure (as below) based on the array [1, 2, 3].
The tutorial JavaScript Data Structures - The Linked List shows how to do this, but I don't really understand the intention to create this.start and this.end variables inside the tutorial.
var list = {
value: 1,
rest: {
value: 2,
rest: {
value: 3,
rest: null
}
}
};
I tried to solve this via the code below.
function arrayToList(array){
var list = { value:null, rest:null};
for(i=0; i<array.length-1; i++)
list.value = array[i];
list.rest = list;
return list;
}
This code gives me an infinite loop of array[0]. What's wrong with my code?
This tutorial shows how to do this but I don't really understand the intention to create this.start and this.end variables inside the tutorial.
The tutorial uses a List wrapper around that recursive structure with some helper methods. It says: "It is possible to avoid having to record the end of the list by performing a traverse of the entire list each time you need to access the end - but in most cases storing a reference to the end of the list is more economical."
This code gives me an infinite loop of array[0].
Not really, but it creates a circular reference with the line list.rest = list;. Probably the code that is outputting your list chokes on that.
What's wrong is with my code?
You need to create multiple objects, define the object literal inside the loop body instead of assigning to the very same object over and over! Also, you should access array[i] inside the loop instead of array[0] only:
function arrayToList(array){
var list = null;
for (var i=array.length-1; i>=0; i--)
list = {value: array[i], rest:list};
return list;
}
This particular data structure is more commonly called cons. Recursion is the most natural (not necessarily the most efficient) way to work with conses. First, let's define some helper functions (using LISP notation rather than "value/rest"):
function cons(car, cdr) { return [car, cdr] }
function car(a) { return a[0] }
function cdr(a) { return a[1] }
Now, to build a cons from an array, use the following recursive statement:
cons-from-array = cons [ first element, cons-from-array [ the rest ] ]
In Javascript:
function arrayToList(array) {
if(!array.length)
return null;
return cons(array[0], arrayToList(array.slice(1)));
}
And the reverse function is similarly trivial:
function listToArray(list) {
if(!list)
return [];
return [car(list)].concat(listToArray(cdr(list)));
}
function arrayToList (arr) {
var list = null;
for (var i = arr.length - 1; i >= 0; i--) {
list = {
value: arr[i],
rest: list
};
}
return list;
}
function prepend (elem, list) {
return {
value: elem,
rest: list
};
}
function listToArray (list) {
var arr = [];
for (var node = list; node; node = node.rest) {
arr.push(node.value);
}
return arr;
}
function nth(list, num) {
if (!list) {
return undefined;
} else if (num === 0) {
return list.value;
} else {
return nth(list.rest, num - 1);
}
}

Needing some visitor-like design pattern

I will give you a sample example of my problem to remove the logical complexity and let you be focus on the important part. Of course, this example will be a bit useless...
I have a tree structure where node are like that
{
path: "...",
childs : []
}
Now, I have to write all the full paths from root to each leaf in an array.
My design is very poor:
function listPaths(node) {
var result = [];
function listForNode(n, parentFullPath) {
var thisPath = parentFullPath + "/" + n.path;
result.push(thisPath);
n.childs.forEach(function (child) {
listForNode(child, thisPath);
});
}
listForNode(node, "");
return result;
}
It could be nice but I can't write the test with Mocha without having an insane 600 line code test file. At this moment, you should be asking why. The reason is the complexity of the real purpose, that's not relevant for my question. My goal is to having something 'mockable' cause I'm used to. (Java dev). But I fail.
Do you have any pattern that I can use to resolve this one? I'm not really good at JS patterns. :/
Visitor? Making an Y Combinator? So many possibility...
Thank you for reading me
You need to remember that functions are first class citizens in javascript.
I see that essentially what you have is something like
function createVisitor(parentsAccumulatorInitialValue, parentsAccumulator){
var visitor = function myVisitor (node) {
var result;
function listForNode(n, parentsAcc) {
var thisPath = parentsAccumulator(parentsAcc, n);
result.push(thisPath);
n.childs && n.childs.forEach(function (child) {
listForNode(child, thisPath);
});
}
result = [];
listForNode(node, parentsAccumulatorInitialValue());
return result;
}
return visitor;
}
var listPaths = createVisitor(
function parentInit () {
return "";
},
function parentAcc (parentFullPath, n) {
return parentFullPath + "/" + n.path;
});
But that's not the only abstraction you could take care of:
function createVisitor2(
totalAccumulatorInitialValue,
totalAccumulator,
parentsAccumulatorInitialValue,
parentsAccumulator){
var visitor = function myVisitor (node) {
var total;
function listForNode(n, parentsAcc) {
var thisPath = parentsAccumulator(parentsAcc, n);
total = totalAccumulator(total, thisPath, n);
n.childs && n.childs.forEach(function (child) {
listForNode(child, thisPath);
});
}
total = totalAccumulatorInitialValue();
listForNode(node, parentsAccumulatorInitialValue());
return total;
}
return visitor;
}
var listPaths2 = createVisitor2(
function totalInit() {
return [];
},
function totalAcc(total, thisPath, n){
total.push(thisPath);
return total;
},
function parentInit () {
return "";
},
function parentAcc (parentFullPath, n) {
return parentFullPath + "/" + n.path;
});
Which might be pretty reasonable, but as you can see, I'm already beginning to have trouble finding appropriate names for these variables. In fact, I'd say the name of our function is bad, as doesn't create anything strictly like a visitor object I know of. However, it does work (BTW, I've slightly modified it to handle nulls as well as empty arrays):
> listPaths( { path:"foo",
childs: [{path:"bar", childs: null}, {path:"bob", childs: null}]})
["/foo", "/foo/bar", "/foo/bob"]
It can be modified even further so that your trees don't strictly even have the same structure... but we're already at 4 parameters, which isn't great. It'd be better if your visitor creator were passed a single extensible object with all the necessary methods or values. For instance, maybe (pseudocode):
function createVisitor3(opts) {
//assume we've defined GetDefaults() somewhere local to createVisitor3
// as well as assume that extend is defined somewhere that copies properties
// into a new object like various previously existing libraries do.
opts = extend({}, GetDefaults(), opts);
var totalAccumulatorInitialValue = opts.totalAccumulatorInitialValue;
var totalAccumulator = opts.totalAccumulator;
var parentsAccumulatorInitialValue = opts.parentsAccumulatorInitialValue;
var parentsAccumulator = opts.parentsAccumulator;
var childrenGetter = opts.childrenGetter;
/// etc.
...
}

How to convert javascript array to function

I have an array of arbitrary values. I Wrote a function that transforms the array to an array of functions that return the original values, so instead of calling a[3], I will call a3.
Here is my code which does not work? code. It gives this error Cannot call method '1' of undefined.
var numToFun = [1, 2, { foo: "bar" }];
var numToFunLength = numToFun.length;
function transform(numTo) {
for (var i = 0; i < numToFunLength; i++) {
(function(num){
numTo.unshift(function() {
return num;
});
}(numTo.pop()))
}
}
var b = transform(numToFun);
console.log(numToFun);
console.log(b[1]());​
Others have already answered your question while I was writing mine but I will post it anyway - this may be somewhat easier to follow without all of those popping and unshifting:
function transform(numTo) {
var r = [];
for (var i = 0; i < numTo.length; i++) {
r[i] = (function (v) {
return function() {
return v;
}
}(numTo[i]));
}
return r;
}
(I have also changed the hard-coded length from numToFunLength to numTo.length so the transform() function would work for other inputs than only the global numToFun variable.)
See DEMO.
UPDATE: even more elegant way to do it using the Sugar library:
function transform(array) {
return array.map(function (v) {
return function() {
return v;
}
});
}
I like this syntax because it makes it more explicit that you want to map an array of values to an array of functions that return those values.
See DEMO.
Your function transform does not return anything. That is why b is undefined.
return numTo;
jsFiddle Demo
On the other hand, the array will be passed to the function as a reference anyways, so the original array will be changed. It is not a problem if you don't return anything, just omit the var b = transform(numToFun); line and simply write transform(numToFun).
Your transform function isn't returning anything. So b is undefined

Categories

Resources