6 ms·
I really like this js question (whiteboarding): Implement function foo which takes an integer size, and returns an array of that size where each element in tha
by mkoryak 12y ago
I really like this js question (whiteboarding):
Implement function foo which takes an integer size, and returns an array of that size where each element in that array is a function that returns the index of that function in the array. Testcase: 42 === foo(1000)[42]()
There are 3 different correct solutions. Discuss which solution is better, worse... etc (if they get there)
(could probably be worded better, I'm not an english major)
- serve_yay 12y ago:(
- speg 12y agoI feel bad, because as I was writing a solution to this I knew why it wouldn't work and why (returning my counter variable returns the value at the end of the count) but I still couldn't come up with a fix :( Edit: A good Google seems to suggest using JSON.stringify and JSON.parse to copy the value. Edit 2: But even that doesn't seem to work :( Edit 3: Got it, using a generator function. Which makes sense. I guess I'm not an expert yet! :)
- tcqag 12y agoHere's a solution using closure: http://codepen.io/anon/pen/KwmQam http://codepen.io/anon/pen/KwmQam
- b3tta 12y agoUsing a closure: function foo(s) { function generator(i) { return function () { return i; }; } var r = new Array(s); for (var i = 0; i < s; i++) { r[i] = generator(i); } return r; } console.log(foo(1000)[42]()); Using Function.prototype.bind(): function foo(s) { function generator(i) { return i; } var r = new Array(s); for (var i = 0; i < s; i++) { r[i] = generator.bind(window, i); } return r; } console.log(foo(1000)[42]());
- deleted 12y ago[deleted]
- jnbiche 12y agoIt's a good question, and a pretty fair one for a Javascript developer to know, given the role that closures play in the language. That said, I'm not thinking of a 3rd solution. Closures(best?), a global(worse), what else? Edit: As Daiz points out, the bind I was thinking of doesn't even have to even be to a global. But we still have seen only two solutions: variations of binding and closures. What's the third? Inquiring minds want to know!
- mkoryak 12y agoThe 3 solutions that I came up with are: - bind - function creator outside of the loop called from within - create an anon function on each loop iteration that acts like the function creator in #2 The bind is best in terms of memory and simplicity, but will not run on on IE 8 or crappier, so in that case #2 is preferred. The last one creates anon functions needlessly, but is very compact to write.
- jcrowe206 12y agofourth solution would be naming the function with the iterator (as in my example below) and calling indexOf(iterator) when the function is invoked
- jusski 12y ago5 solution with eval function foo(s) { a = Array(s); for (var i = 0; i < s; i++) { a[i] = eval('(function () { return ' + i + '})'); } return a; }
- deleted 12y ago[deleted]
- bbotond 12y agoThe only solution I could think of is this: function foo(n) { var result = []; for (var i = 0; i < n; i++) (function(j) { result.push(function() { return j; }); })(i); return result; } What are the two others?
- serve_yay 12y agoThat's using a closure, another would be to use Function.prototype.bind (but really that's still using a closure, just putting it out of sight), can't think of any others.
- jnbiche 12y ago>Function.prototype.bind (but really that's still using a closure, just putting it out of sight), How is `bind` still using a closure? `bind` just allows users to alter a function's execution context. However, the implementation varies according to the JS engine. Some of them may use a closure internally as a part of the process, but I don't think V8 does.
- serve_yay 12y agoSure, I was cheating there a little bit. I was thinking in terms of how one would actually implement bind in user land JS code, which would use a closure. V8's implementation of bind likely does not.
- Daiz 12y agoYou could use Function.prototype.bind in a couple ways, or even Array.prototype.map (though sadly you can't really do new Array(n).map, if that was true you could make this a one-liner). // new Array(n) could just be [] in all examples // // using Array.prototype.map // sadly you can't do new Array(n).map // because it doesn't iterate over undefined functions function foo(n) { for (var ret = new Array(n), i = 0; i < n; ++i) { ret[i] = i; } return ret.map(function(_,n) { return function() { return n; }; }); } // using Function.prototype.bind in a couple ways function foo(n) { function num() { return +this; } for (var ret = new Array(n), i = 0; i < n; ++i) { ret[i] = num.bind(i); } return ret; } function foo(n) { function num(a) { return a; } for (var ret = new Array(n), i = 0; i < n; ++i) { ret[i] = num.bind(null, i); // could bind this to pretty much whatever here } return ret; }
- shawndumas 12y agovar foo = function (len) { return Array(len) .join(0) .split(0) .map(function (e, i) { return function () { return i; }; }); };
- evunveot 12y agoI may have discovered the worst correct answer: var foo = function (arr, i) { if (typeof arr === 'number') { arr = new Array(arr); foo(arr, arr.length - 1); return arr; } if (i === -1) { return; } arr[i] = function () { return i; } foo(arr, i - 1); };
- jcrowe206 12y agoHere's another one. Probably not very performant function foo(count) { var ret = [] for (var i=0; i < count; i++) { ret [i] = function i() { return this.indexOf(i) } } return ret; }
- tcqag 12y agoJust fyi indexOf is O(n), which means if you tried to do: var count = 1000000; var arr = foo(count); for (var i = 0; i < count; i++) arr[i](); It will take O(n^2) and will probably never complete whereas all the other solutions here will probably take ~1second.