Recursion - javascript - javascript

I am trying to solve an extra credit problem using recursion. Basically there is a "tree" that has matching "leaves" and I need to use recursion to check those matching leaves and return true if they match and return false if they do not.
I have no idea how to do this and no materials I can find are helping me understand recursion any better. This is for an online program to learn how to program.
Any help would be appreciated!
Psuedo:
// initialize some value
// initialize some flag.. boolean
// initialize some helper function and pass obj...leaf checker recursive function
// check all the keys ...for loop/forEach
// if a key is an object && value is undefined
// assign value
// return
// if a value is an object ==> recurse
// if a value is found and it doesn't match our initial value
// trip our flag to false
// return
// return true or false
const checkMatchingLeaves = (obj) => {
};
My attempt:
const checkMatchingLeaves = (obj) => {
// return true if every property on `obj` is the same
// otherwise return false
let checker = Object.values(obj);
if (Object.values(obj).length === 1) return true;
if (checker.map(checker[i] === checker[i + 1])) {
i > checker.length; i++;
}
};

This isn't exactly what (I think) you're asking for, but you should be able to use it as a template to figure out what to do:
// searchTree takes a value to try to match and an array/primitive
// value.
function searchTree(val, node) {
// Check if it's a value or an array. If it's a value we can
// do the test and return, otherwise we recursively call
// searchTree on all the children.
// Array.some returns true if any of the function calls return
// true. This is a shorthand for your boolean flag: it lets us
// return early as soon as we find a match.
return Array.isArray(node) ?
node.some(child => searchTree(val, child)) : // recursive call
val === node;
}
searchTree(3, [1, 2, [8], [[[3]]]]); // true
searchTree('abc', 'a'); // false
searchTree('abc', ['ab', 'bc', ['abc']]); // true
This is a DFS search implementation.

Related

How to handle calling functions on data that may be undefined?

I primarily work with React and often find that when I write a function that relies on a component's state, I have to perform a check to see if the piece of state is defined before performing any actions.
For example: I have a function that uses .map() to loop over an array of objects fetched from a database and generates jsx for each object in the array. This function is called in the render() function of my component. The first time render() is called, the initial array is empty. This results in an error because, of course, the first index of the array is undefined.
I have been circumventing this by making a conditional check to see if the value of the array is undefined or not. This process of writing an if statement each time feels a little clumsy and I was wondering if there is a better way to perform this check or a way to avoid it entirely.
Check the array before using map:
arr && arr.map()
OR,
arr && arr.length && arr.map() // if you want to map only if not empty array
OR,
We can even use like this (as commented by devserkan):
(arr || []).map()
As per your comment:
I wish there was a safe navigation operator like with C# (arr?.map())
Yes, obviously. This is called optional chaining in JavaScript which is still in proposal. If it is accepted, then you may use like this:
arr?.map()
You can see it in staging 1 for which you may use babel preset stage1
But obviously, except the checking array length, your requirement will not be fulfilled:
This results in an error because, of course, the first index of the array is undefined.
So, I suggest you to use:
arr && arr.length && arr.map()
What you actually need here is called optional chaining:
obj?.a?.b?.c // no error if a, b, or c don't exist or are undefined/null
The ?. is the existential operator and it allows you to access properties safely and won't throw if the property is missing. However optional chaining is not yet part of JavaScript but has been proposed and is in stage 3, see State 3 of TC39.
But, using proxies and a Maybe class, you can implement optional chaining and return a default value when the chain fails.
A wrap() function is used to wrap objects on which you want to apply optional chaining. Internally, wrap creates a Proxy around your object and manages missing values using a Maybe wrapper.
At the end of the chain, you unwrap the value by chaining getOrElse(default) with a default value which is returned when the chain is not valid:
const obj = {
a: 1,
b: {
c: [4, 1, 2]
},
c: () => 'yes'
};
console.log(wrap(obj).a.getOrElse(null)) // returns 1
console.log(wrap(obj).a.b.c.d.e.f.getOrElse(null)) // returns null
console.log(wrap(obj).b.c.getOrElse([])) // returns [4, 1, 2]
console.log(wrap(obj).b.c[0].getOrElse(null)) // returns 4
console.log(wrap(obj).b.c[100].getOrElse(-1)) // returns -1
console.log(wrap(obj).c.getOrElse(() => 'no')()) // returns 'yes'
console.log(wrap(obj).d.getOrElse(() => 'no')()) // returns 'no'
wrap(obj).noArray.getOrElse([1]).forEach(v => console.log(v)) // Shows 1
wrap(obj).b.c.getOrElse([]).forEach(v => console.log(v)) // Shows 4, 1, 2
The complete example:
class Maybe {
constructor(value) {
this.__value = value;
}
static of(value){
if (value instanceof Maybe) return value;
return new Maybe(value);
}
getOrElse(elseVal) {
return this.isNothing() ? elseVal : this.__value;
}
isNothing() {
return this.__value === null || this.__value === undefined;
}
map(fn) {
return this.isNothing()
? Maybe.of(null)
: Maybe.of(fn(this.__value));
}
}
function wrap(obj) {
function fix(object, property) {
const value = object[property];
return typeof value === 'function' ? value.bind(object) : value;
}
return new Proxy(Maybe.of(obj), {
get: function(target, property) {
if (property in target) {
return fix(target, property);
} else {
return wrap(target.map(val => fix(val, property)));
}
}
});
}
const obj = { a: 1, b: { c: [4, 1, 2] }, c: () => 'yes' };
console.log(wrap(obj).a.getOrElse(null))
console.log(wrap(obj).a.b.c.d.e.f.getOrElse(null))
console.log(wrap(obj).b.c.getOrElse([]))
console.log(wrap(obj).b.c[0].getOrElse(null))
console.log(wrap(obj).b.c[100].getOrElse(-1))
console.log(wrap(obj).c.getOrElse(() => 'no')())
console.log(wrap(obj).d.getOrElse(() => 'no')())
wrap(obj).noArray.getOrElse([1]).forEach(v => console.log(v)) // Shows 1
wrap(obj).b.c.getOrElse([]).forEach(v => console.log(v)) // Shows 4, 1, 2

findKey() - recreating lodash library method

I've got a problem with a CodeCademy task. I am to re-create the findKey lodash library method. Here there are the steps of how to do it, but I got stuck, especially at point 5.
Add a method to our _ object called findKey.
Add two parameters to this method: object and predicate. We will
name our predicate function parameter predicate since this is the
name used in the Lodash documentation.
Within the method, use a for ... in loop to iterate through each key
in object.
Within the loop, create a variable called value and set it equal to
the value at the current key in object.
Still within the loop, create another variable called
predicateReturnValue and set it equal to the result of calling
predicate with value.
Finally, still within the loop, use an if statement to check
if predicateReturnValue is truthy. If it is, return the current key
from the method.
Outside of the loop, return undefined to address all cases where no
truthy values were returned from predicate.
This is my code that doesn't work:
findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue === 'true') {
return value;
};
};
return undefined;
}
I appreciate your help!
You need to return the key after the truty check of the call of predicate.
function findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue) { // just take the value
return key; // return key
}
}
}
const
isStrictEqual = a => b => a === b,
object = { a: 'foo', b: 'bar', c: 'baz' }
console.log(findKey(object, isStrictEqual('bar')));
console.log(findKey(object, isStrictEqual('cat')));

Javascript - every() method to check isInteger on array elements

I want to check return true if an array contains all integers or false if not. I am trying to use the every method MDN docs every.
So if given '1234' it will return true and if given '123a' it would return false.
function validatePIN (pin) {
pinArray = pin.split("");
if (pinArray.length === 4 || pinArray.length === 6) {
if (pinArray.every(Number.isInteger()) === true;) {
return true
}};
How does every pass the element to isInteger so it can test it?
Even if you fix syntax error and pass Number.isInteger as a function this won't work.
function wrongValidatePIN (pin) {
var pinArray = pin.split(""); // <-- array of strings
if (pinArray.length === 4 || pinArray.length === 6) {
if (pinArray.every(Number.isInteger)) { // <-- isInteger works with numbers
return true
}}
return false
}
console.log(wrongValidatePIN('1234'))
You need something like this
function validatePIN (pin) {
var pinArray = pin.split(""); // <-- array of strings
return (pinArray.length === 4 || pinArray.length === 6)
&& pinArray.every(char => !Number.isNaN(Number.parseInt(char, 10)))
}
console.log(validatePIN('1234'), validatePIN('123a'))
Or you could use regexp
function validatePin(pin) {
return /^(\d{4}|\d{6})$/.test(pin)
}
console.log(validatePin('1234'), validatePin('123456'),
validatePin('12345'), validatePin('123a'))
As the comments stated, the isInteger function can be passed as an argument by calling pinArray.every(Number.isInteger) instead of calling it a single time, (or by providing it inside a function .every(c=>Number.isInteger(c)) , but passing the function itself is more concise)
However, it's unlikely to provide the result you expect, because isInteger checks if the value is an actual integer, not if the value can be parsed to one.
That could be resolved with something like pinArray.map(parseFloat).every(Number.isInteger);
but then it would be easier to use !pinArray.some(isNaN)
That could make the function:
function validatePIN (pin) {
return (pin.length === 4 || pin.length === 6)
&& ![...pin].some(isNaN);
}
But as a final note, regular expressions are made for this type of check and could be preferable here
Your pin.split("") will never work when you pass number eg. 1234 as argument. Convert to string first then split pin.toString().split("").
Now inside .every() function we cast our string to number by doing +number.
return pinArray.every(number => Number.isInteger(+number));
.every() returns true or false.
Here is working example.
function validatePIN(pin) {
var pinArray = pin.toString().split("");
if (pinArray.length === 4 || pinArray.length === 6) {
// returns true or false
// +number casts string into number
return pinArray.every(number => Number.isInteger(+number));
}
// We assume that every PIN is not valid
return false;
};
console.log('test1', validatePIN(1234)); // true
console.log('test2', validatePIN('1234')); // true
console.log('test3', validatePIN('123a')); // false
console.log('test4', validatePIN('0001')); // true

Trying to understand the syntax of this .contain() function

the contain function below is written based on .reduce() function:
_.reduce = function(collection, iterator, accumulator) {
each(collection,function(value){
accumulator=iterator(accumulator,value);
});
return accumulator
};
Im kinda confused by the syntax here, or is it written logically? why we use if statement first and return 'wasFound' first, before set item===target? isn't if item===target is true, we set wasFound to true?
_.contains = function(collection, target) {
return _.reduce(collection, function(wasFound, item) {
if (wasFound) {
return true;
}
return item === target;
}, false);
};
The first time the reduce function makes a match (return item === target) it will subsequently return true for all remaining items to be iterated. There is no reason to check if future values match the target because we only care if the collection contains the target at least 1 time. That is why if wasFound is true it simply returns true.
You use it like this:
_.contains([1,2,3], 2);
//=> true
_.contains([1,2,3], 5);
//=> false
It takes a list and an element. It sets wasFound to false initially and then for each item in the collection checks: (1) if wasFound is true, then some previous item has been identical to target, so set wasFound to true to maintain it, (2) otherwise, set wasFound to the value of item === target.

Check if value exists in random n-dimensional array Javascript

I am writing a function that checks if a n-dimensional array has a certain value:
function checkVal(array, value) {
if (value exists) {
return true;
} else {
return false;
}
}
My problem is that I want this function to work for any array regardless of its number of dimensions or types of elements. I tried to first flatten the array, but only managed to do it for a couple of dimensions.
EDIT:
Some examples of possible arrays:
var arr1 = ['1','3',['a','b'],'4,5'];
var arr2 = ['a','b',['c','d',['e',['e',['e',['e',['e',['e',['e',['e',['e',['e',['f',['f',['f',['f',['f',['f',['g',['g',['g',['g',['g',['g',['g',['h']]]]]]]]]]]]]]]]]]]]]]]]]];
There's no need to flatten the array, that's just extra work. What you need is a recursive function:
function checkVal(array, value) {
// `Array#some` loops through the array until the iterator
// function returns true; it returns true if the iterator
// does at some point, false otherwise
return array.some(function(entry) {
// If this entry in the array is an array, recurse
if (Array.isArray(entry)) {
return checkVal(entry, value);
}
// It isn't, do an equality check
return entry === value;
});
}
Array#some and Array.isArray are both ES5 functions, so present in any modern browser, and both can be shimmed/polyfilled for older ones like IE8. Or, of course, the above can be rewritten with a boring for loop and the old Object.prototype.toString.call(entry) === "[object Array]" test for whether something is an array.
Note that I've used === for the equality check. If you need something more complicated, like object equivalence rather than identity, etc., make the change there.
Example/basic tests:
function checkVal(array, value) {
// `Array#some` loops through the array until the iterator
// function returns true; it returns true if the iterator
// does at some point, false otherwise
return array.some(function(entry) {
// If this entry in the array is an array, recurse
if (Array.isArray(entry)) {
return checkVal(entry, value);
}
// It isn't, do an equality check
return entry === value;
});
}
snippet.log(checkVal(['a', 'b', 'c'], 'b')); // true
snippet.log(checkVal(['a', 'b', 'c'], 'd')); // false
snippet.log(checkVal([['a'], ['b', 'c']], 'c')); // true
snippet.log(checkVal([['a'], ['b', 'c']], 'd')); // false
snippet.log(checkVal([['a'], [['b', ['c']]]], 'c')); // true
snippet.log(checkVal([['a'], [['b', ['c']]]], 'd')); // false
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
You need a recursive function to check in all child of your array
function searchValue(arr, val){
// found another array
if(arr instanceof Array){
for(var i=0; i<arr.length; i++){
if(searchValue(arr[i],val)){
return true; // stop on first valid result
}
}
return false;
}else{
// found a leaf
return arr == val; // <-- if you want strict check, use ===
}
}
if(searchValue(myArray, 'my variable')){
// do something..
}
it works in any browsers

Categories