_.each function for looping in JS issue - javascript

We are asked to do the following:
Write a function called checkValue that searches an array for a value. It takes an array and a value and returns true if the value exists in the array, otherwise it returns false.
var helloArr = ['bonjour', 'hello', 'hola'];
var checkValue = function(arr, val) {
//checks if the val is in arr
}
Rewrite checkValue using _.each.
here is what I have to itterate over helloArr using _.each:
var helloArr = ['bonjour', 'hello', 'hola'];
var checkValue = function (num) {
return num;
}
checkValue('hola');
var output = us.each(helloArr, function(num){
if (checkValue())
{return true;}});
return output;
What am I doing wrong? When I run it with node, theres no errors but no output either. I know you can use _.find to do this but the spec is asking to itterate over the array and find the value using _.each.

In your second example, you're calling checkValue without a parameter, so it's going to return undefined, which is a falsey value, and the callback to each never returns anything.
Then again, it doesn't normally need to return anything anyway. _.each returns the list it operates on.
_.each is like a for-loop; consider treating it more like one.
function checkValue_original1(arr, val) {
for (var i = 0; i < arr.length; i++) {
if (val == arr[i]) return true;
}
return false;
}
function checkValue_original2(arr, val) {
return arr.indexOf(val) >= 0;
}
function checkValue_us_each(arr, val) {
var found = false;
_.each(arr, function(element, index, list) {
if (element == val) found = true;
});
return found;
}

Related

Javascript break/return function within function

I have always been confused about the best way to handle this. The method I have been using in the past works but it seems like there has to be a better way.
Below I have a section of code that I'm wanting to return item for the function getData. Problem is in the example below it's returning for the forEach function not the getData function.
function getData() {
var array = ["element1","element2"];
array.forEach(function (item) {
if (item == "element2") {
return item;
}
});
}
I have been doing something like this to overcome this.
function getData() {
var array = ["element1","element2"];
var returnValue;
array.forEach(function (item) {
if (item == "element2") {
returnValue = item;
}
});
if (returnValue) {
return returnValue;
}
}
Is there a better way to handle this? Seems like those extra 4 lines of code just create confusion and clutter in my code.
You could use Array#some
The some() method tests whether some element in the array passes the test implemented by the provided function.
function getData() {
var array = ["element1","element2"];
var returnValue;
array.some(function (item) {
if (item == "element2") {
returnValue = item;
return true;
}
});
return returnValue;
}
Or, if you use ES6, use Array#find
The find() method returns a value in the array, if an element in the array satisfies the provided testing function. Otherwise undefined is returned.
function getData() {
var array = ["element1","element2"];
return array.find(item => item == "element2");
}
You can readily do this with Array#indexOf:
function getData() {
var array = ["element1","element2"];
var index = array.indexOf("element2");
return index === -1 ? null : array[index];
}
In that case, it works because what you're looking for is an === match for what you have. The more general case is a case for Array#find, which is an ES2015 thing but you can easily shim/polyfill it for ES5 and below:
function getData() {
var array = ["element1","element2"];
return array.find(function (item) {
return item == "element2";
});
}
...which lets you specify the match based on a more complex condition.
You could just use indexOf:
return array[array.indexOf("element2")];
If it doesn't find the value, the index will be -1. And index -1 of any array will be undefined.

Test if Tree contains Object

I need a function to check if an object exists in a tree.
I recursively run through the tree and use lodash to check for equality of objects:
var objectInResultList = function (obj, list) {
list.forEach(function (item) {
if (_.isEqual(item, obj) === true) {
return true
}
else if (item.children.length > 0) {
return objectInResultList(obj, item.children);
}
});
return false;
};
var item = {"name":"Enterprise1.1","description": "testTest","children":[]};
var resultList = [{"name":"Enterprise1.1","description": "testTest","children":[{"name":"Enterprise1.1","description": "testTest","children":[]}]}];
var ret = objectInResultList(item, resultList);
alert(ret);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.min.js"></script>
The function should return true if the item is in the list and otherwise return false, but currently it always returns false.
Can someone find my problem?
JSFiddle
You are missing a couple of things.
A minor thing - your predicate is not returning false if the objects don't match and it has no children.
You are returning true/false from the predicate, but aren't using it anywhere so objectInResultList always returns false.
Rather than using forEach, it is easier to use find or findIndex, and the use the result of that to determine what to return from objectInResultList. For example if find returns undefined because of no match, then you return false.
In this case, you are using a tree with multiple lists, so using find makes more sense than findIndex.
var objectInResultList = function (obj, list) {
// call find to get the matching object
var match = list.find(function (item) {
if (_.isEqual(item, obj) === true) {
return true;
}
else if (item.children.length > 0) {
return objectInResultList(obj, item.children);
}
else {
return false;
}
});
// if match is undefined return false. If we found a match, return true
return !_.isUndefined(match);
};
var item = {"name":"Enterprise1.1","description": "testTest","children":[]};
var resultList = [{"name":"Enterprise1.1","description": "testTest","children":[{"name":"Enterprise1.1","description": "testTest","children":[]}]}];
var ret = objectInResultList(item, resultList);
alert(ret);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.min.js"></script>
forEach() has no return-value and it ignores any returned value. So returning true or false in the search-function is useless.
You should use a better iterator-function.
var objectInResultList = function (obj, list) {
function search(item){
if(item == null) return false;
if(_.isArray(item)) return _.some(item, search);
if(_.isEqual(item, obj)) return true;
return search(item.children);
}
return search(list);
};

Why would my find method return undefined?

I'm recreating a number of Underscore.js methods to study JavaScript and programming in general.
Below is my attempts to recreate Underscore's _.find() method.
var find = function(list, predicate) { // Functional style
_.each(list, function(elem){
if (predicate(elem)) {
return elem;
}
});
};
var find = function(list, predicate) { // Explicit style
if (Array.isArray(list)) {
for (var i = 0; i < list.length; i++) {
if (predicate(list[i])) {
return list[i];
}
}
} else {
for (var key in list) {
if (predicate(list[key])) {
return list[key];
}
}
}
};
My second find method, which is using for loop and for in loop works. Whereas, my first find method would return undefined. I believe both should do the same work. However, they don't. Would someone please point what is going on?
Your return is only returning from the inner (nested) function and your find function is indeed not returning anything, hence the undefined.
Try this instead:
var find = function(list, predicate) { // Functional style
var ret;
_.each(list, function(elem){
if (!ret && predicate(elem)) {
return ret = elem;
}
});
return ret;
};

How to filter an array?

Guys, please don't answer me to use a JavaScript library to solve this problem, I'm using VanillaJS.
Suppose I have an array with 10,000 string records, same as following:
var arr = [
'John',
'Foo',
'Boo',
...
'Some',
'Beer'
];
Please note that the array doesn't follow any sort.
Now, I want to find items with oo in the text, what is the best way to do? Should I populate a new array or just pop items that don't match with the criteria?
You can make use of the filter method, which will create a new array with all the elements that passes the condition.
arr.filter(function(x){ return x.indexOf ('oo') > -1});
If you want to use filter method in every browser you could add the polyfill method (see link) in your code.
Another option (slightly faster) with basic javascript would be:
Looping trough the array with a simple for loop and test on your condition.
var filtered = [];
for(var i=0, length=arr.length; i<length; i++){
var current = arr[i];
if(current.indexOf('oo') > -1){
filtered.push(current);
}
}
my approch
forEach function
function forEach(array, action) {
for(var i=0; i<array.length; i++)
action(array[i]);
}
partial function
function asArray(quasiArray, start) {
var result = [];
for(var i = (start || 0); i < quasiArray.length; i++)
result.push(quasiArray[i]);
return result;
}
function partial(func) {
var fixedArgs = asArray(arguments, 1);
return function() {
return func.apply(null, fixedArgs.concat(asArray(arguments)));
};
}
contains method for String obj
if (!String.prototype.contains) {
String.prototype.contains = function (arg) {
return !!~this.indexOf(arg);
};
}
filter function:
function filter(test, array) {
var result = [];
forEach(array, function(element) {
if (test(element))
result.push(element);
});
return result;
}
test function for test array items
function test(key, el) {
return el.contains(key);
}
finally
filter(partial(test, 'oo'), arr);
NO shortcuts ( p.s. you said I want to find items , not filter - hence my answer)
simple loop :
var g=arr.length; //important since you have big array
for( var i=0;i<g;i++)
{
if ( g[i].indexOf('oo')>-1)
{
console.log(g[i]);
}
}
If you want to filter (without polyfill)
var g=arr.length; //important since you have big array
var h=[];
for( var i=0;i<g;i++)
{
if ( g[i].indexOf('oo')>-1)
{
h.push(g[i]);
}
}
//do something with h
A very simple way, use forEach:
var result = [];
arr.forEach(function (value) {
if (value.indexOf('oo') !== -1) {
result.push(value);
}
});
or map:
var result = [];
arr.map(function (value) {
if (value.indexOf('oo') !== -1) {
result.push(value);
}
});

Function with forEach returns undefined even with return statement

I'm just making a function for checking a value of something in my object array, but for some reason it keeps returning undefined. Why is that?
Demo: http://jsfiddle.net/cNYwz/1/
var data = [{
"Key": "1111-1111-1111",
"Email": "test#test.com"
}, {
"Key": "2222-2222-2222",
"Email": "test#boo.com"
}];
function getByKey(key) {
data.forEach(function (i, val) {
if (data[val].Key === key) {
return data[val].Key;
} else {
return "Couldn't find";
}
});
}
var asd = getByKey('1111-1111-1111');
console.log(asd);
In your function, you're returning from the function passed to forEach, not from getByKey.
You could adapt it like this :
function getByKey(key) {
var found = null;
data.forEach(function (val) {
if (val.Key === key) {
found = val;
}
});
return found;
}
But this would iterate over all elements, even if the item is immediately found. That's why you'd better use a simple for loop :
function getByKey(key) {
for (var i=0; i<data.length; i++) {
if (data[i].Key === key) {
return data[i];
}
}
}
Note that I also adapted your code to return the value, not the key. I suppose that was the intent. You might also have been confused with another iteration function : the first argument passed to the callback you give to forEach is the element of the array.
Your function getByKey has no return statement. The two returns are for the anonymous function used by forEach.
You're not returning anything to the outer scope, try this alternative:
function getByKey(key) {
var result = data.filter(function (i, val) {
return data[val].Key == key;
});
return result.length ? result : 'Not found';
}
Try storing the positive result as a variable, and then returning that variable (or a "Couldn't find" in case nothing is written) at the end of the function after the forEach loop.
function getByKey(key) {
var result;
data.forEach(function (val, i) {
if (data[val].Key === key) {
result = data[val].Key;
}
});
return result || "Couldn't find";
}
In addition to the ideas in the other answers, you're better off using Array.prototype.some, rather than forEach. That will let you stop when you find the first match:
function getByKey(key) {
var found = null;
data.some(function (val) {
if (val.Key === key) {
found = val;
return true; //stop iterating
}
});
return found;
}
You might also consider using filter, which can return an array containing just the objects where key matches:
function filter_array_by_key(key){
return data.filter(function(v){
return v.Key===key;
};
}
To get the first matching object, you can then use filter_array_by_key(key)[0], which will yield undefined if there was no match.

Categories

Resources