JavaScript's 'forEach' misunderstanding - javascript

This function works properly:
function task02(arr) {
var out = [];
arr = arr.forEach(function(item, i){
(item > 0) ? out.push(1) : out.push(0);
});
return out;
}
And this one's not (outputs undefined):
function task02(arr) {
arr = arr.forEach(function(item, i){
(item > 0) ? item = 1 : item = 0;
});
return arr;
}
I've tried using both item and item[i], but it's not working. Can someone please explain to me, why this is not working?

Can someone please explain to me, why this is not working?
JavaScript is pass/call/assign by value. That implies that assigning a value to a variable won't magically change the value of another variable (or an array element).
Simpler example:
var foo = 42;
var bar = foo;
foo = 21;
bar will still have the value 42.
In your case, assigning to item won't change the array element.
As always, if you use an unfamiliar method, read its documentation first.

The callback function in your second example doesn't have any side-effects. It just iterates over the array, does the comparison and that's it. This is the main difference between .forEach (which iterates over the array, but returns undefined) and array methods such as .map, .filter, .reduce that iterate, execute the callback on every item and return a modified array.
If you want to avoid a temporary array you should use Array.map in this case:
function task02(arr) {
return arr.map(function(item, i){
return (item > 0) ? 1 : 0;
});
}

Related

Check if a word matches another in a map function in JS [duplicate]

I would like to filter an array of items by using the map() function. Here is a code snippet:
var filteredItems = items.map(function(item)
{
if( ...some condition... )
{
return item;
}
});
The problem is that filtered out items still uses space in the array and I would like to completely wipe them out.
Any idea?
EDIT: Thanks, I forgot about filter(), what I wanted is actually a filter() then a map().
EDIT2: Thanks for pointing that map() and filter() are not implemented in all browsers, although my specific code was not intended to run in a browser.
You should use the filter method rather than map unless you want to mutate the items in the array, in addition to filtering.
eg.
var filteredItems = items.filter(function(item)
{
return ...some condition...;
});
[Edit: Of course you could always do sourceArray.filter(...).map(...) to both filter and mutate]
Inspired by writing this answer, I ended up later expanding and writing a blog post going over this in careful detail. I recommend checking that out if you want to develop a deeper understanding of how to think about this problem--I try to explain it piece by piece, and also give a JSperf comparison at the end, going over speed considerations.
That said, **The tl;dr is this:
To accomplish what you're asking for (filtering and mapping within one function call), you would use Array.reduce()**.
However, the more readable and (less importantly) usually significantly faster2 approach is to just use filter and map chained together:
[1,2,3].filter(num => num > 2).map(num => num * 2)
What follows is a description of how Array.reduce() works, and how it can be used to accomplish filter and map in one iteration. Again, if this is too condensed, I highly recommend seeing the blog post linked above, which is a much more friendly intro with clear examples and progression.
You give reduce an argument that is a (usually anonymous) function.
That anonymous function takes two parameters--one (like the anonymous functions passed in to map/filter/forEach) is the iteratee to be operated on. There is another argument for the anonymous function passed to reduce, however, that those functions do not accept, and that is the value that will be passed along between function calls, often referred to as the memo.
Note that while Array.filter() takes only one argument (a function), Array.reduce() also takes an important (though optional) second argument: an initial value for 'memo' that will be passed into that anonymous function as its first argument, and subsequently can be mutated and passed along between function calls. (If it is not supplied, then 'memo' in the first anonymous function call will by default be the first iteratee, and the 'iteratee' argument will actually be the second value in the array)
In our case, we'll pass in an empty array to start, and then choose whether to inject our iteratee into our array or not based on our function--this is the filtering process.
Finally, we'll return our 'array in progress' on each anonymous function call, and reduce will take that return value and pass it as an argument (called memo) to its next function call.
This allows filter and map to happen in one iteration, cutting down our number of required iterations in half--just doing twice as much work each iteration, though, so nothing is really saved other than function calls, which are not so expensive in javascript.
For a more complete explanation, refer to MDN docs (or to my post referenced at the beginning of this answer).
Basic example of a Reduce call:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
// if condition is our filter
if (iteratee > 1) {
// what happens inside the filter is the map
memo.push(iteratee * 2);
}
// this return value will be passed in as the 'memo' argument
// to the next call of this function, and this function will have
// every element passed into it at some point.
return memo;
}, initialMemo)
console.log(array) // [4,6], equivalent to [(2 * 2), (3 * 2)]
more succinct version:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Notice that the first iteratee was not greater than one, and so was filtered. Also note the initialMemo, named just to make its existence clear and draw attention to it. Once again, it is passed in as 'memo' to the first anonymous function call, and then the returned value of the anonymous function is passed in as the 'memo' argument to the next function.
Another example of the classic use case for memo would be returning the smallest or largest number in an array. Example:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
// ^this would return the largest number in the list.
An example of how to write your own reduce function (this often helps understanding functions like these, I find):
test_arr = [];
// we accept an anonymous function, and an optional 'initial memo' value.
test_arr.my_reducer = function(reduceFunc, initialMemo) {
// if we did not pass in a second argument, then our first memo value
// will be whatever is in index zero. (Otherwise, it will
// be that second argument.)
const initialMemoIsIndexZero = arguments.length < 2;
// here we use that logic to set the memo value accordingly.
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
// here we use that same boolean to decide whether the first
// value we pass in as iteratee is either the first or second
// element
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
// memo is either the argument passed in above, or the
// first item in the list. initialIteratee is either the
// first item in the list, or the second item in the list.
memo = reduceFunc(memo, this[i]);
// or, more technically complete, give access to base array
// and index to the reducer as well:
// memo = reduceFunc(memo, this[i], i, this);
}
// after we've compressed the array into a single value,
// we return it.
return memo;
}
The real implementation allows access to things like the index, for example, but I hope this helps you get an uncomplicated feel for the gist of it.
That's not what map does. You really want Array.filter. Or if you really want to remove the elements from the original list, you're going to need to do it imperatively with a for loop.
Array Filter method
var arr = [1, 2, 3]
// ES5 syntax
arr = arr.filter(function(item){ return item != 3 })
// ES2015 syntax
arr = arr.filter(item => item != 3)
console.log( arr )
You must note however that the Array.filter is not supported in all browser so, you must to prototyped:
//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var res = new Array();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this)
{
var val = this[i]; // in case fun mutates this
if (fun.call(thisp, val, i, this))
res.push(val);
}
}
return res;
};
}
And doing so, you can prototype any method you may need.
TLDR: Use map (returning undefined when needed) and then filter.
First, I believe that a map + filter function is useful since you don't want to repeat a computation in both. Swift originally called this function flatMap but then renamed it to compactMap.
For example, if we don't have a compactMap function, we might end up with computation defined twice:
let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.filter(x => {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
return isIncluded;
})
.map(x => {
let computation = x / 2 + 1;
return `${x} is included because ${computation} is even`
})
// Output: [2 is included because 2 is even, 6 is included because 4 is even]
Thus compactMap would be useful to reduce duplicate code.
A really simple way to do something similar to compactMap is to:
Map on real values or undefined.
Filter out all the undefined values.
This of course relies on you never needing to return undefined values as part of your original map function.
Example:
let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.map(x => {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
if (isIncluded) {
return `${x} is included because ${computation} is even`
} else {
return undefined
}
})
.filter(x => typeof x !== "undefined")
I just wrote array intersection that correctly handles also duplicates
https://gist.github.com/gkucmierz/8ee04544fa842411f7553ef66ac2fcf0
// array intersection that correctly handles also duplicates
const intersection = (a1, a2) => {
const cnt = new Map();
a2.map(el => cnt[el] = el in cnt ? cnt[el] + 1 : 1);
return a1.filter(el => el in cnt && 0 < cnt[el]--);
};
const l = console.log;
l(intersection('1234'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('12344'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('1234'.split``, '33456'.split``)); // [ '3', '4' ]
l(intersection('12334'.split``, '33456'.split``)); // [ '3', '3', '4' ]
First you can use map and with chaining you can use filter
state.map(item => {
if(item.id === action.item.id){
return {
id : action.item.id,
name : item.name,
price: item.price,
quantity : item.quantity-1
}
}else{
return item;
}
}).filter(item => {
if(item.quantity <= 0){
return false;
}else{
return true;
}
});
following statement cleans object using map function.
var arraytoclean = [{v:65, toberemoved:"gronf"}, {v:12, toberemoved:null}, {v:4}];
arraytoclean.map((x,i)=>x.toberemoved=undefined);
console.dir(arraytoclean);

Find whether Value in Object exists within an array

I am trying to find whether the value roomTypeFilter exists within an Object inside an array. I then want to perform conditional statements depending whether the value roomTypeFilter exists or not.
Below is my code
function includes(k) {
for (var i = 0; i < this.length; i++) {
if (this[i] === k || (this[i] !== this[i] && k !== k)) {
return true;
}
}
return false;
}
var dayValue = this.ui.dayConstraintList.val();
var arr = [courseTemplate.get('dayConstraints')[dayValue]];
console.log(arr);
arr.includes = includes;
console.log(arr.includes('roomTypeFilter'));
The first console.log returns an Object inside an array.
The second console.log returns false, in this case as roomTypeFilter exists inside the Object I want to return 'true' but I am unsure how to do so, any help would be greatly appreciated.
Instead of using includes, use hasOwnProperty. Take a look here for more information on the hasOwnProperty. It's pretty self-explanatory from its name - it essentially returns a boolean on whether or not the object has a property. I.e., in your case, you would use:
arr[0].hasOwnProperty('roomTypeFilter');
You can use hasOwnProperty method to check if object contains roomTypeFilter property.
...
if (this[i].hasOwnProperty(k)) {
...
}
...
You could refactor your includes function to use
array.prototype.some
some() executes the callback function once for each element present in the array until it finds one where callback returns a truthy value... If such an element is found, some() immediately returns true.
Here is an example.
var arr = [
{
roomTypeFilter: {
name: 'foo'
}
},
["roomTypeFilter", "foo"],
"roomTypeFilter foo"
]
function includes(arr, k) {
return arr.some(function(item) {
return item === Object(item) && item.hasOwnProperty(k);
})
}
console.log("Does arr includes roomTypeFilter ? - ", includes(arr, 'roomTypeFilter'))

Can forEach in JavaScript make a return? [duplicate]

This question already has answers here:
What does `return` keyword mean inside `forEach` function? [duplicate]
(2 answers)
Why does this forEach return undefined when using a return statement
(5 answers)
Closed 1 year ago.
I wonder if forEach in JavaScript can make a return, here is my code:
var a = [0, 1, 2, 3, 4];
function fn(array) {
array.forEach(function(item) {
if (item === 2) return false;
});
return true;
}
var ans = fn(a);
console.log(ans); // true
I want to find out if 2 is in my array, if so, return false, but it seems that the forEach function has looped the whole array and ignore return.
I wonder if I can get the answer I want with forEach ( I know I can get what I want using for(..))? dear friend, pls help me, with great thanks!
You can use indexOf instead https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
function fn(array) {
return (array.indexOf(2) === -1);
}
Also from the documentation for forEach - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
Note: There is no way to stop or break a forEach() loop other than by
throwing an exception. If you need such behaviour, the .forEach()
method is the wrong tool, use a plain loop instead.
So, the return value cannot be used the way you are using it. However you could do a throw (which is not recommended unless you actually need an error to be raised there)
function fn(array) {
try {
array.forEach(function(item) {
if (item === 2) throw "2 found";
});
}
catch (e) {
return false;
}
return true;
}
In this case .indexOf() is probably what you want, but there's also .some() when a simple equality comparison is too simple:
var ans = a.some(function(value) { return value === 2; });
The .some() function returns true if the callback returns true for any element. (The function returns as soon as the callback does return true, so it doesn't bother looking beyond the first match.)
You can usually use the .reduce() function as a more general iteration mechanism. If you wanted to count how many instances of 2 were in your array for example:
var twos = a.reduce(function(c, v) { if (v === 2) c += 1; return c; }, 0);
Others have mentioned .indexOf() and .some(). I thought I would add that a good old fashioned for loop gives you the absolute most iteration control because you control the iteration and your processing code is not embedded in a callback function.
While .indexOf() already does exactly what you need, this code just shows how you can directly return when using the old fashioned for loop. It is somehow out of favor these days, but is often still the best choice for better looping control.
function fn(array) {
for (var i = 0, len = array.length; i < len; i++) {
if (array[i] === 2) return false;
}
return true;
}
Using the for loop, you can iterate backwards (useful when removing items from the array during the iteration), you can insert items and correct the iteration index, you can immediately return, you can skip indexes, etc...
forEach returns undefined by specification. If you want to find out if a particular value is in an array, there is indexOf. For more complex problems, there is some, which allows a function to test the values and returns true the first time the function returns true, or false otherwise:
a.some(function(value){return value == 2})
Obviously a trivial case, but consider if you want to determine if the array contains any even numbers:
a.some(function(value){return !(value % 2)})
or as an ECMA2015 arrow function:
a.some(value => !(value % 2));
If you want to test if a particular value is repeated in an array, you can use lastIndexOf:
if (a.indexOf(value) != a.lastIndexOf(value) {
// value is repeated
}
or to test for any duplicates, again some or every will do the job:
var hasDupes = a.some(function(value, i, a) {
return a.lastIndexOf(value) != i;
});
An advantage of some and every is that they only process members of the array until the condition is met, then they exit whereas forEach will process all members regardless.
You said you want with forEach, so I modified your code:
function fn(array) {
var b = true;
array.forEach(function (item) {
if (item === 2) {
b = false;
}
});
return b;
}
var a = [0, 1, 2, 3, 4];
function fn(array, callback) {
var r = true;
array.forEach(function(item) {
if (item === 2) r = false;
});
callback(r);
}
fn(a, function(data) {
console.log(data) //prints false.
});
You can use callbacks as mentioned above to return the data you need. This is not same as the return statement but you will get the data.

Javascript: Determine if all of the elements in the array are keys in the object

I am trying to figure out if all of the elements in an array are keys in the object.
var obj = { name: 'Computer', cost: '$1,000' };
var myArray = [ 'name', 'cost', 'bio' ]; //another example would be var myArray = [];
for(var x = 0; x < myArray.length; x++){
if (myArray[x] in obj)
{
return true;
}
}
How can I check if all of the elements in an array are keys in the object?
Do it the other way around. If you find someone in the array who is NOT in the object then you return false. If you reach the end of the loop then you return true because all the keys were in the object.
Depending on what you want, this might do the trick:
function hasKeys(obj, keys) {
for (var i=0; i != keys.length; ++i) {
if (!(keys[i] in obj))
return false;
}
return true;
};
One subtlety you need to ask yourself: do you want to know if the object has the keys directly (i.e. not somewhere in its prototype stack?) If so, then replace keys[i] in obj with obj.hasOwnProperty(keys[i])
function hasKeys(obj, keys) {
return keys.every(Object.prototype.hasOwnProperty.bind(obj));
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every states, "The every method executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value (a value that becomes false when converted to a Boolean). If such an element is found, the every method immediately returns false. Otherwise, if callback returned a true value for all elements, every will return true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values" (emphasis mine).
Array.some() makes for a clean solution.
// object in question
var obj = { ... };
// keys that need to be present in the object
var keys = [ ... ];
// iterate through the whitelist until we find a key that doesn't exist in the object. If all exist, that means Array.some() is false.
var valid = !keys.some(function(key) {
return !obj.hasOwnProperty(key);
});
An alternative solution would be using a similar concept, but with Array.every(). It is to note that this will generally be slower because it always has to touch every element in the whitelist.
// iterate through the whitelist, making sure the object has each key.
var valid = keys.every(obj.hasOwnProperty);
This problem can be expressed in terms of set inclusion: does the set of property keys completely include the array of required keys? So we can write it as
includes(Object.keys(obj), arr)
So now we just need to write includes.
function includes(arr1, arr2) {
return arr2.every(function(key) {
return contains(arr1, key);
}
}
For contains, we could use Underscore's _.contains, or just write it ourselves:
function contains(arr, val) {
return arr.indexOf(val) !== -1;
}
If we are interested in conciseness at the possible expense of readability, we could shorten our definition of includes to use Function#bind instead of the anonymous function:
function includes(arr1, arr2) {
return arr2.every(contains.bind(0, arr1));
}
Now we have functions we can use for other things, instead of mixing up the two different aspects of the problem--the keys of an object, and set inclusion. If we really want to write an all-in-one function, it becomes the somewhat more readable:
function hasMany(obj, arr) {
return arr.every(_.contains.bind(0, Object.keys(obj));
}
If we want more readability, like we were writing a novel:
function object_has_required_keys(object, required_keys) {
var object_keys = Object.keys(object);
function key_is_present(key) {
return object_keys.indexOf(key) !== -1;
}
return required_keys.every(key_is_present);
}
Underscore's _.intersection
If we're lazy (or smart), we could use Underscore's _.intersection to implement includes:
function includes(arr1, arr2) {
return _.intersection(arr1, arr2).length === arr2.length;
}
The idea is to take the intersection, and if the first array includes the second entirely, then the intersection will contain all the elements of the second array, which we can check by comparing their lengths.
Using ES6 sets
Thinking ahead to ES6, we could implement include using its sets, which ought to be faster:
function includes(arr1, arr2) {
var set = new Set(arr1);
return arr2.every(Set.prototype.has.bind(set));
}

Object (string or array) NAME. how to get it?

I need a prototype done in this way:
Array.prototype.getname=function(){ [...]return arrayname; }
So I can:
z=new Array;
alert(z.name);
and I should have "z" in the alert.
I'm working on Chrome and caller/callee seem to return empty.
The best you can do is to always explicitly set the array's name when you create it:
var z = [];
z.name = 'z';
You could do this by having a function makeArray that sets the name passed as an argument:
function makeArray(name) {
var arr = [];
arr.name = name;
return arr;
}
The essential problem is that the several variables can point to the same array:
var z = [],
x = z;
Then what should the name be: z or x?
The problem is that a variable (like an array) can have several names. For example:
var a = new Array();
var b = a;
a[0] = "hello";
alert(b[0]);//"hello"
What is the name of the array, a or b?
Can't be done. There is no way to access the name of the variable which is storing a reference to the object. Perhaps you should explain why you need behavior like this, so someone can suggest you an alternative way to approach the problem.
The only way to do this would be to brute-force check all properties of the global object (assuming the variable is global) until you find a property that === the array. Of course, it could be referenced by multiple variables so you would have to pick one of the names you get. This implementation gets the first variable to reference the array and will work in browsers and web worker threads:
Array.prototype.getName = function () {
var prop;
for (prop in self) {
if (Object.prototype.hasOwnProperty.call(self, prop) && self[prop] === this) {
return prop;
}
}
return ""; // no name found
};
Of course, I don't recommend this at all. Do not do this.
Further testing the object.getName().. i found this 'problem':
test1='test'
test
test2='test'
test
test1.getName()
test1
test2.getName()
test1
this happens because they have the same content and getName checks for content.
a solution could be to return an Array in that case.
But I'm still searching for a definitive solution to this brainteasing problem.
So For now the best answer is Elijah's
More generally:
Object.prototype.getName = function () {
var prop;
for (prop in self) {
if (Object.prototype.hasOwnProperty.call(self, prop) && self[prop] === this && self[prop].constructor == this.constructor) {
return prop;
}
}
return ""; // no name found
};
I wonder if there are better solutions.

Categories

Resources