array and asynchronous function callback - javascript

I got async function:
var func = function (arg, next) {
var milliseconds = 1000;
setTimeout(function(){
console.log (arg);
next()
} , milliseconds);
}
And array:
var arr = new Array();
arr.push (0);
arr.push (1);
console.log(arr);
I want to use func for every item of my array arr:
func(arr[0], function(){
func(arr[1], function(){
console.log("finish");
})
})
Ok for array consisted of 2 elements, but if I got array of 1000 elements how to use func for every item in arr?
How to do it in cycle?

var arrayFunc = function(array) {
if (array.length > 0) {
func(array[0], function() { arrayFunc(array.slice(1)); });
}
}
This will run your function with the first element in the array, and then have the continuation function take the rest of the array. So when it runs it will run the new first element in the array.
EDIT: here's a modified version that doesn't copy the array around:
var arrayFunc = function(array, index) {
if (index < array.length) {
func(array[index], function() {
var newI = index + 1;
arrayFunc(array, newI);
});
}
}
And just call it the first time with an index of 0.

While your approach is valid, it's not possible to use it if you have an uncertain number of calls, since every chain in your async command is hardcoded.
If you want to apply the same functionality on an array, it's best to provide a function that creates an internal function and applies the timeout on it's inner function:
var asyncArraySequence = function (array, callback, done){
var timeout = 1000, sequencer, index = 0;
// done is optional, but can be used if you want to have something
// that should be called after everything has been done
if(done === null || typeof done === "undefined")
done = function(){}
// set up the sequencer - it's similar to your `func`
sequencer = function(){
if(index === array.length) {
return done();
} else {
callback(array[index]);
index = index + 1;
setTimeout(sequencer, timeout);
}
};
setTimeout(sequencer, timeout);
}
var arr = [1,2,3];
asyncArraySequence(arr, function(val){console.log(val);});

A simple asynchronous loop:
function each(arr, iter, callback) {
var i = 0;
function step() {
if (i < arr.length)
iter(arr[i++], step);
else if (typeof callback == "function")
callback();
}
step();
}
Now use
each(arr, func);

You may try arr.map
var func = function (arg, i) {
var milliseconds = 1000;
setTimeout(function(){
console.log (arg);
}, milliseconds*i);
}
var arr = new Array();
arr.push (0);
arr.push (1);
arr.map(func);
Demo and Polyfill for older browsers.
Update : I thought the OP wants to loop through the array and call the callback function with each array item but I was probably wrong, so instead of deleting the answer I'm just keeping it here, maybe it would be helpful for someone else in future. This doesn't answer the current question.

Thanx, #Herms. Working solution:
var arrayFunc = function(array) {
if (array.length > 0) {
func(array[0], function() {arrayFunc(array.slice(1)); });
}
else
{
console.log("finish");
}
}
arrayFunc(arr);

A simple solution would be:
var fn = arr.reduceRight(function (a, b) {
return func.bind(null, b, a);
}, function() {
console.log('finish');
});
fn();
demo: http://jsbin.com/isuwac/2/
or if the order of func's parameters could be changed to receive the next callback as the first parameter, it could be as simple as:
['a', 'b', 'c'].reduceRight(func.bind.bind(func, null), function (){
console.log('finish');
})();
demo: http://jsbin.com/ucUZUBe/1/edit?js,console

You can loop through the array
for(var i = 0; i < arr.length; i++){
func(arr[i], function(){...});
}

Related

Functional Programming: What's the difference between using a closure and using the bind method?

I'm working on a tutorial that explains functional programming. He asked me to come with a solution and it worked, but his solution uses the .bind method of the function.
Is there a difference between our solutions other than the syntax?
function mapForEach(arr, fn) {
var newArr = [];
for(var i = 0; i < arr.length; i++){
newArr.push(fn(arr[i]));
}
return newArr;
}
var arr1 = [1,2,3,4,5];
var checkPassedLimitWithBind = function(limiter){
return function (limiter, item) {
return item >= limiter;
}.bind(this, limiter);
};
var checkPassedLimitWithClosure = function(limiter){
return function (item) {
return item >= limiter;
};
};
var notPassed3 = mapForEach(arr1, checkPassedLimitWithBind(3));
var doesNotPass3 = mapForEach(arr1, checkPassedLimitWithClosure(3));
alert(notPassed3);
alert(doesNotPass3);
The examples can be found here as well:
https://jsfiddle.net/podbarron/73m86cj3/
There is absolutely no behavior difference because that function does not use this.
Otherwise it would be different, yes:
var checkPassedLimitWithBind = function(limiter) {
return function (limiter, item) {
return this == item;
}.bind(this, limiter);
};
var checkPassedLimitWithClosure = function(limiter) {
return function (item) {
return this == item;
};
};
console.log( checkPassedLimitWithBind.call(123)(123) ); // true
console.log( checkPassedLimitWithClosure.call(123)(123) ); // false
The bind solution is unnecessarily complicated. There's no need to partially apply the limiter value there since the function can pretty much access it directly.
Both will end up working the same way. However, it can be different if the variable ever gets reassigned (you'd never want to do it with function arguments).
var checkPassedLimitWithBind = function(limiter){
var fn = function (limiter, item) {
return item >= limiter;
//limiter === argument value for limiter parameter
}.bind(this, limiter);
limiter = 5;
return fn;
};
var checkPassedLimitWithClosure = function(limiter){
var fn = function (item) {
return item >= limiter;
//limiter === 5 all the time
};
limiter = 5;
return fn;
};
Answering the post title: Basically, the closure will have access to whatever value that reference is holding. When you bind the function you'll get that specific value passed down.

return object if list<object> value is exists (Javascript, jquery grep/map)

I'm using grep and map functions to get the object if the value is exists in the list, but it does not work well.
I have a list customList and the customObject has the int id property and List value properties.
customobject[0].id
customObject[0].value[]
What I want is check if in the List the value 5 exists.
The function what I'm using is:
var gettedcustomObject = $.grep(customList, function (e) {
var result = e.Value.map(function (a) { return a === 5;});
return result;
});
What am I doing wrong and what is the correct implementation?
Note: 2x foreach could be a solution, but customList has more than 1000 objects with 10000 values. I think that slow down the proces.
This should do it.
var gettedcustomObject = customList.filter(function(v){
var ln = v.Value.length;
for(var i = 0; i < ln; i++){
if(v.Value[i] == 5){
return true;
}
}
return false;
// Or simply:
// return v.Value.indexOf(5) != -1;
});
This will work if v.Value is an array.
You should look at some: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#Polyfill
Way faster than the other methods like filter, map or sort as it was designed for this.
//List to work against
var arr = [];
//Populate
while (arr.length < 9999999) {
arr.push(Math.random() * 999999)
}
//Set element to find
arr[10] = "test";
//Begin timing
var d = new Date().getTime();
//Run filter
console.log(arr.filter(function(a){return a === "test"}).length > 0);
//How long did it take
console.log("`filter` took:",new Date().getTime() - d,"ms")
//Begin timing
d = new Date().getTime();
//Run filter
console.log(arr.some(function(a){return a === "test"}));
//How long did it take
console.log("`some` took:",new Date().getTime() - d,"ms")
<script>
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#Polyfill
// Production steps of ECMA-262, Edition 5, 15.4.4.17
// Reference: http://es5.github.io/#x15.4.4.17
if (!Array.prototype.some) {
Array.prototype.some = function(fun/*, thisArg*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.some called on null or undefined');
}
if (typeof fun !== 'function') {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t && fun.call(thisArg, t[i], i, t)) {
return true;
}
}
return false;
};
}
</script>
If your goal is to find the first object in the list that contains 5 in the Value property, then you're looking for Array#find and Array#indexOf:
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.indexOf(5) != -1;
});
Note that Array#find was added relatively recently and so you may need a polyfill for it (which is trivial). MDN has one.
Or you could use Array#includes instead of indexOf, which will be in ES2017 and is also polyfillable:
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.includes(5);
});
Live Example (using indexOf):
var customList = [
{
note: "I'm not a match",
Value: [2, 3, 4]
},
{
note: "I'm not a match either",
Value: [78, 4, 27]
},
{
note: "I'm a match",
Value: [889, 5, 27]
},
{
note: "I'm also a match, but you won't find me",
Value: [4, 6, 5]
}
];
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.indexOf(5) != -1;
});
console.log(gettedcustomObject);
If your logic matching the item inside Value were more complicated, you'd use Array#some and a callback function rathe than indexOf. But when looking to see if an array for an entry in an array based on ===, indexOf or the new Array#includes are the way to go.
one approach using Array.some() and Array.indexOf(). some loop break once the element is found
var gettedcustomObject;
customobject.some(function(obj){
if(obj.value.indexOf(5) >-1){
gettedcustomObject = obj;
return true;
}
});

JavaScript Remove Multiple Values from Array Using Filter and Loop

I'm new here and need some help with writing a function destroyer() to remove multiple values from an array.
The destroyer() function passes in an array and additional numbers as arguments. The idea is to remove the numbers from the array.
E.g.
destroyer([1, 2, 3, 1, 2, 3], 2, 3)
Output: [1, 1]
destroyer(["tree", "hamburger", 53], "tree", 53)
Output: ["hamburger"]
destroyer([2, 3, 2, 3], 2, 3)
Output: []
Note: the examples only show 2 additional numbers to remove. But the function destroyer() should be able to remove any number of values (i.e. 4, 5, or 6 parameters).
However, my code does not produce the same result. Specifically, using console.log, I see that my filterer function does not loop properly.
1) Can anyone help me debug?
2) Any better way to write this function?
Thank you very much!!!
function destroyer() {
var args = Array.prototype.slice.call(arguments);
var itemToRemove = args.slice(1);
console.log(itemToRemove);
var newArr = args[0];
console.log(newArr);
function filterer(value) {
for (var i = 0; i < itemToRemove.length; i++) {
console.log(i);
console.log(itemToRemove[i]);
if (value != itemToRemove[i]) {
return value;
}
}
}
return newArr.filter(filterer);
}
Your filterer function can be much simpler:
function filterer (value) {
return itemToRemove.indexOf(value) === -1;
}
Using Array.prototype.indexOf() can be inefficient compared to object property lookup in terms of time complexity. I would recommend looping through the additional arguments once and constructing an object with target elements to be destroyed as keys. Then you can check if a given value is a target or not within a filtering callback that you pass to Array.prototype.filter().
function destroyer() {
var arr = arguments.length && arguments[0] || [];
var targets = {};
for (var i = 1; i < arguments.length; i++) {
targets[arguments[i]] = true;
}
return arr.filter(function (x) {
return targets[x] === undefined;
});
}
One downside to this approach is that not all values in JS can be valid properties of an object, since properties must be strings. In this case, you're just using numbers as keys, and those numbers are implicitly converted to strings.
We can pass the arguments an extra parameter to our callback function in our filter() method.
function destroyer(arr) {
return arr.filter(filterer(arguments)); // Pass arguments
}
function filterer(args) {
return function(value) { // Actual filter function
for (var i = 1; i < args.length; i++) {
if (value === args[i]) // Seek
return false; // Destroy
}
return true; // Otherwise keep
};
}
This passes all 5 test cases for freeCodeCamp | Basic Algorithm Scripting | Seek and Destroy.
The following code will remove elements from an array. The elements it removes are defined by any extra parameters. ...remove is an ES6 feature that aggregates extra parameters into a single array.
I will iterate over the ...remove array and delete that element from the main array we are working on.
Here is a JSFiddle: https://jsfiddle.net/zzyopnnp/
...extra_parameters is not supported in most browsers, you may want to use the arguments object.
function removeIndex(array, index) {if(index>-1){array.splice(index, 1);}}
function destroyer(array, ...remove) {
remove.forEach(function(elem, index) {
removeIndex(array, index);
});
};
var arr = ["tree", "hamburger", 53];
destroyer(arr, "tree", 53);
console.log(arr);
A simple function
function filter(arr, arg1, arg2){
var j = arr.length;
while(j){
if (arr.indexOf(arg1) > -1 || arr.indexOf(arg2) > -1){
arr.splice(j - 1, 1);
}
j--
}
}
For multiple arguments
A simple function
function filter(){
var j = -1;
for(var i = 1; i < arguments.length; i++){
j = arguments[0].indexOf(arguments[i]);
if(j > -1){
arguments[0].splice(j, 1);
}
}
return arguments[0];
}
you can call this function with no of args
eg:
filter([1,2,3,4,5,6,7,8,9], 1, 3, 5); //return [2,4,6,7,8,9]
filter([1,2,3,4,5,6,7,8,9], 1); //return [2,3,4,5,6,7,8,9]
There are really good answers here, but you can do it very clean in this way, remember you have an objects option in filter method which you can use in the callback function, in this case i'm using it like : arguments[i] so I can check every value in the arguments array
function destroyer(arr) {
for(var i = 1; i < arguments.length; i++){
arr = arr.filter(isIn, arguments[i]);
}
function isIn(element,index, array){
if (element != this){
return element;
}
}
return arr;
}

javascript iterate through and map a multi-dimensional array

I want to apply a function to each of the values at all levels of the array:
arr = [[1,2,3],[1,2,3],[[1,2],[1,2]],1,2,3]
for example, multiply all the values by 3, and map it in the same format as before so I get:
arr = [[3,6,9],[3,6,9],[[3,6],[3,6]],3,6,9]
What would be the best way to go about this?
I tried to use a recursive function:
function mapall(array){
array.map(function(obj){
if (Array.isArray(obj)===true) { return mapall(obj) }
else{ return obj*3 }
})
};
but when I run it I just get undefined, so I must be doing something not quite right??
Any ideas??
Thanks
Everything was working, but you forgot to return from array.map. Here's a cleaner version of your code:
var arr = [[1,2,3],[1,2,3],[[1,2],[1,2]],1,2,3];
function mapAll(array){
return array.map(function(item){
return Array.isArray(item) ? mapAll(item) : item * 3;
});
}
alert(JSON.stringify(mapAll(arr)));
Version with callback function where you can do with array elements what you want (el * 2 or something else)
var arr = [[1,2,3],[1,2,3],[[1,2],[1,2]],1,2,3];
function mapAll(array, cb) {
for (var i = 0, len = array.length; i < len; i++) {
if (Array.isArray(array[i])) {
mapAll(array[i], cb);
} else {
array[i] = cb(array[i]);
}
}
return array;
};
var res = mapAll(arr, function (el) {
return el * 3;
});
console.log(JSON.stringify(res));

How is `each` different from `for-loop` when returning a value?

I have my each function which I created to emulate Underscore.js's _each() for my Javascript study.
var each = function(list, iteratee) {
if (Array.isArray(list)) { // list is array
for (var i = 0; i < list.length; i++) {
iteratee(list[i], i, list);
}
} else if (list.constructor === Object) { // list is object
for (var key in list) {
iteratee(list[key], key, list);
}
}
};
Then I wanted to create a function find which is also available from Underscore.js. This function looks through each value in the list, returning the first one that passes a truth test (predicate), or
undefined if no value passes the test. The function returns as soon as it finds an acceptable element and doesn't traverse the entire list.
Here is my version of find that I came up with.
var find = function(list, predicate) {
each(list, function(elem){
if (predicate(elem)) {
return elem;
}
});
};
I thought it would return a value immediately after it has found a true value for an element that passes a test from an external predicate function. But instead, it's giving me an undefined.
Below code works as I expected. But why would they provide different output?
var find = function(list, predicate) {
if (Array.isArray(list)) { // list is array
for (var i = 0; i < list.length; i++) {
if (predicate(list[i])) {
return list[i];
}
}
} else if (list.constructor === Object) { // list is object
for (var key in list) {
if (predicate(list[key])) {
return list[key];
}
}
}
};
What I don't understand is that why doesn't each works as I expected when I included it in my find function. Wouldn't they simply different in terms of their style of expression? In other word, one is functional style, and another is not?
This is caused due to the lack of return statement.
Each function iterates over find but doesn't return anything. return statement in predicate returns the output to the each function where it is not expected
Example of working function:
var find = function(list, predicate) {
var res = undefined/null/whatever;
each(list, function(elem) {
if (predicate(elem)) {
res = elem;
}
});
return res;
};
However this function is not efficient as it won't stop when result is found
This has to do with how return works. Let's look at your code:
var find = function(list, predicate) {
// you pass list and an anonymous callback to `each`
each(list, function (elem) {
// if this condition is true
if (predicate(elem)) {
// return elem
return elem;
}
});
}
The problem is that return elem applies to the anonymous callback, not the find function.
If you want to be able to "break" the each loop, you can check the current state on each iteration of the for-loop within each.
// only going to write for arrays
var each = function (list, iteratee) {
for (var i = 0; i < list.length; i++) {
if (iteratee(list[i], i, list)) continue;
else break;
}
});
// then in find:
var find = function (list, predicate) {
var ret = null
each(list, function(elem) {
if (predicate(elem)) {
ret = elem;
return false; // return false, since we no longer wish to continue
}
});
return ret;
};
A second solution is to return from within the each loop:
var each = function (list, iteratee) {
for (var i = 0; i < list.length; i++) {
if (iteratee(list[i], i, list)) {
continue;
} else {
return list[i];
}
}
// didn't find anything, so `return null`
return null;
});
var find = function (list, predicate) {
return each(list, function(elem) {
// if `predicate`, return false, so the loop breaks
return !predicate(elem);
});
};
The only problem I have with this solution is that it distorts the meaning of each. each intuitively means "go through everything," which the second solution doesn't necessarily do.

Categories

Resources