I have a requirement where I need to access an array element using its function.
For example, I have Array A[], now I want to create array B, such that
A[i] === B[i].value()
I tried below code but I am getting error as B[i].value is not a function
<script>
function test(A) {
var B = new Array();
for(var i=0; i<A.length; i++) {
B[i] = function value() {
return A[i];
};
}
for(var i=0; i< B.length; i++) {
console.log(B[i].value());
}
return B;
}
A=[1,2,3];
B = test(A);
</script>
What is the correct way for this?
You need to assign an object instead:
B[i] = {
value: function () {
return A[i];
}
}
To avoid any problems with the scope of i, you can use the statement let
The let statement declares a block scope local variable, optionally initializing it to a value.
function test(A) {
var B = new Array();
for (let i = 0; i < A.length; i++) {
B[i] = {
value: function() {
return A[i];
}
};
}
for (let k = 0; k < B.length; k++) {
console.log(B[k].value());
}
return B;
}
var B = test([1, 2, 3]);
console.log(B)
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could make value anonymous e.g. B[i] = function () { /* Your code */ } then just call B[i]() instead of B[i].value()
Related
I want to make a function for a nested for loop in order to avoid having to copy and paste the loop.
I can make a nested for loop into an array so that I only need to copy-paste a single for loop, but that basically means that it takes twice as long to run.
Of course, I can save that array so the function would only need to be called once, but it would be nice if there was a way to send arguments to that function.
I wrote an example for my idea:
function exampleForLoop(num){
let arr = [];
for (let i = 0; i < 2; i++){
for (let j = 0; j < num; j++){
for (let k = 0; k < 3; k++){
arr.push([i,j,k]);
}
}
}
return arr;
}
let exampleArr = exampleForLoop(3);
for (let i = 0; i < exampleArr.length; i++){
console.log(exampleArr[i]);
}
let exampleArr2 = exampleForLoop(1);
for (let i = 0; i < exampleArr2.length; i++){
console.log(exampleArr2[i]);
}
You could go even a step ahead and use a recursive function for the loops along with an array of limits for each loop (starting with zero) and hand over a function which parameters correspond to the looped values.
function loop(limits, fn, values = [], result = []) {
if (!limits.length) {
result.push(fn(...values));
return result;
}
for (let i = 0, l = limits.shift(); i < l; i++) {
loop([...limits], fn, [...values, i], result);
}
return result;
}
loop([2, 3, 3], (...a) => a).forEach(a => console.log(...a));
console.log('');
loop([2, 1, 3], (...a) => a).forEach(a => console.log(...a));
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you make each code that would be in the for loop a separate function, you can send the names of those functions as a parameter of the for loop function, and then you can use functionName(i, j, k) to call them.
Code:
function exampleForLoop(functionName, num){
for (let i = 0; i < 2; i++){
for (let j = 0; j < num; j++){
for (let k = 0; k < 4; k++){
functionName(i, j, k);
}
}
}
}
function exampleFunction1(i, j, k){
console.log(i, j, k);
}
function exampleFunction2(i, j, k){
console.log(i, j, k);
}
exampleForLoop(exampleFunction1, 3);
exampleForLoop(exampleFunction2, 1);
I know how do closures work, but it is not very clear to me.
How does the below snippet works under the hood (output's 0) :
function fillFunctionArr() {
let arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = {
inner: i,
innerFunc: function() {
console.log(this.inner)
}
}
}
return arr;
}
var ex = fillFunctionArr();
ex[0].innerFunc()
Sure, if it were declared as :
arr[i] = {
// inner: i,
innerFunc: function() {
console.log(i)
}
}
The output will be 10.
Why is the first snippet more preferable than the below one:
function fillFunctionArr() {
let arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = (function(qnt) {
return function() {
console.log(qnt)
}
})(i);
}
return arr;
}
var ex = fillFunctionArr();
ex[0]()
There is no 'preferable' choice. The choice depends on logic of outer code, that you want to extend. Both initialized immediately on cycle iteration. It's just one of the edges of JS flexibility.
I have a function urlScores which return an array of object in the form
[{"url":"facebook","score":2},{"url":"reddit","score":1},{"url":"stackoverflow","score":3}]
I am asked to sort this array in regards to its score using bubble sort.
What I have tried doing is creating a bubble sorting function that takes the object returned from urlScores and sorts it.
function sort(object)
{
for(var i= 0; i < object.length; i++){
if (object[i].score > object[i+1].score) {
var temp = object[i]
object[i]=object[i+1]
object[i+1]=temp
}
}
}
And the function that should be called for sorting the array looks like:
function rankedScores(web,pattern)
{
return (sort(urlScores(web,pattern)))
}
This doesn't seem to be working, I am faced with TypeError: object[(i + 1)] is undefined
Any help is appreciated
I have corrected your sort function.
function sort(a) {
for (var i = 0; i < a.length - 1; i++) {
if (a[i].score > a[i + 1].score) {
var temp = a[i]
a[i] = a[i + 1]
a[i + 1] = temp
}
}
return a;
}
Here is an example
var arr= '[{"url":"facebook","score":2},{"url":"reddit","score":1},{"url":"stackoverflow","score":3}]';
console.log(sort(arr));
var a = [{"url":"facebook","score":2},{"url":"reddit","score":1},{"url":"stackoverflow","score":3}];
function bubbleSort(a)
{
var swapped;
do {
swapped = false;
for (var i=0; i < a.length-1; i++) {
if (a[i].score > a[i+1].score) {
var temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
swapped = true;
}
}
} while (swapped);
}
bubbleSort(a);
console.log(a);
I have 2 dim array, which looks like this:
var a = [[1,2,3],[4,5,6],[7,8,9]];
I want to write an iterator which will return one value a time when it's called.
iterator(); //returns 1
iterator(); //returns 2
iterator(); //returns 3
I tried such approach:
function iterator() {
var a = [[1,2,3],[4,5,6],[7,8,9]];
var i, j;
return function() {
for (var i = 0; i < a.length; i++) {
var b = a[i];
for (var j = 0; j < b.length; j++) {
return a[i][j];
}
}
}
};
var a = iterator();
a(); //1
a(); //1
a(); //1
It always returns me first element.
I can try this one:
function iterator() {
var a = [[1,2,3],[4,5,6],[7,8,9]];
var i = 0, j = 0;
return function() {
for (; i < a.length; i++) {
var b = a[i];
for (; j < b.length; j++) {
return a[i][j];
}
}
}
};
Also not works.
But if I try this one:
function test() {
var a = [1,2,3,4,5], i = 0;
return function() {
while (i < a.length) {
return a[i++];
}
}
}
var a = test();
a(); //1
a(); //2
a(); //3
It works fine.
What is the difference here? How to make for loop work?
One other visible problem for me is bounds. How should I stop when I reach array bounds?
Instead of using an inner for-loop for the second dimension you can use a simple if to test the bounds of j
function iterator() {
var a = [[1,2,3],[4,5,6],[7,8,9]];
var i = 0, j = 0;
return function() {
for (; i < a.length; i++) {
var b = a[i];
if (j < b.length){
return a[i][j++];
}
j = 0;
}
return undefined; // reached when there is no value left
}
};
Why do you need a loop at all in this case. You are effectively flattening the array anyway. You could just increment the indices along with a bounds check:
function iterator() {
var a = [[1,2,3],[4,5,6],[7,8,9]], i = 0, j = 0;
return function() {
if (j >= a[i].length) { j = 0; i++; }
if (i >= a.length) { j = 0; i = 0; }
snippet.log( a[i][j++] );
}
};
var x = iterator();
x(); x(); x(); x(); x(); x(); x(); x(); x(); x();
x(); x(); x(); x(); x(); x(); x(); x(); x(); x();
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
It is generally not a good idea to extend standard feature, but for a didactical example I will make an exception. For real use, I suggest to implement your own class.
General Idea
Array.prototype.beginIterator = function()
{
var counter = 0;
return function()
{
if (counter<=this.length) return this[counter++];
else return undefined;
};
}
Then you could iterate like follow:
var a = [3,1,4,1,5];
var it = a.beginIterator();
for (var i=it(); i!=undefined; i=it())
{
alert(i);
}
This at the moment work only with single-dimension array, but it could be applied with any logic to other arrays or object.
Multi-dimensional (Any) solution:
The following iterator allow any-dimension array in any combination:
Array.prototype.beginIterator = function()
{
var counter = 0;
var iterators = null;
return function()
{
val = undefined;
if (iterators!=null)
{
val = iterators();
if (val!==undefined) return val;
else
{
iterators = null;
counter++;
}
}
while (counter <=this.length)
{
if (!(this[counter] instanceof Array)) return this[counter++];
else
{
iterators = this[counter++].beginIterator();
val = iterators();
if (val!==undefined) return val;
}
}
return undefiend;
};
}
Example of use:
var a = [3,[3,5,7],4,[1,[2,5,8]],5];
var it = a.beginIterator();
for (var i=it(); i!=undefined; i=it())
{
alert(i);
}
Just when I thought I understood closures...
The following code snippet:
function f() {
var a = [];
var i;
for (i = 0; i < 3; i++) {
a[i] = function () {
var x = i;
return x;
}
}
return a;
}
var a = f();
console.log(a[0]());
console.log(a[1]());
console.log(a[2]());
prints out 3, 3, 3. I don't understand why. I'm copying the value of 'i' to the local variable x, so there should be three x's: x0=0, x1=1. x2=2. How are all of them reading the final value of i?
Your problem is caused by each a[i] being, in fact, a closure. They all share the same i, which is evaluated when each a[i] is called, not when the loop executes. You need to create each closure with a separate context. For instance:
function f() {
var a = [];
var i;
for (i = 0; i < 3; i++) {
a[i] = makeClosure(i);
}
return a;
}
function makeClosure(i) {
return function () {
var x = i;
return x;
}
}
Even though the value of i changes in your for loop, it's still the same i variable. You need to shadow i in that scope and effectively pass it by value:
for (var i = 0; i < 3; i++) {
(function(x) {
a[x] = function() {
return x;
}
})(i);
}