I'm stuck with one of curriculum in freeCodeCamp.org
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/arguments-optional
The below code is what I wrote.
In that code, addTogether(2)(3) should be 5.
But instead of that, addTogether(2)(3) is "undefined"
what's the problem?
I read all hints from freecodecamp forum. But I don't get it.
function addTogether() {
var checkNum = function(x) {
if (typeof x === "number") {
return x
} else {
return undefined
}
}
if (arguments.length > 1) {
if (checkNum(arguments[0]) !== undefined && checkNum(arguments[1]) !== undefined) {
return arguments[0] + arguments[1]
} else {
return undefined
}
} else {
var a = arguments[0]
if (checkNum(a) === undefined) {
return undefined
} else {
return function(args2) {
args2 + a
}
}
}
return false;
}
console.log(addTogether(2)(3))
Your returned function doesn't have a return value. You could use
return function(args2) {
return args2 + a
}
Or
return (args2) => args2 + a
function addTogether(a,b) {
if (arguments.length==2){
if (typeof a == "number" && typeof b == "number"){
return a + b;
}
}
if(arguments.length==1){
if (typeof a == "number"){
return function(b){
if (typeof b == "number"){
return a + b;
}
};
}
}
}
Related
Alright Stackoverflow first post here. I am at a loss, and would appreciate any help.
I have a recursive function that seems to be working properly up until I try and return from it. (Just a little maze runner for fun)
When reaching the return statement it seems to loop back to the if(grid[y+1][x] ===2) statement.
Then I don't see the function getting called again, but the values for y and x start changing as it loops around the function before getting to the else at the bottom and returning there.
I also see the "inside return if" in the console, and setting break points in the browser shows the return statement gets called, just doesn't exit the function.
Many thanks in advance!!!
const grid =[0,0,0,0,3,2],
[0,0,0,0,3,0],
[0,0,0,0,3,0],
[3,3,3,3,3,0],
[0,0,0,0,0,0],
[1,3,3,3,3,3]
],
const recursiveSearch = (y, x) => { // init values y=5 x=0
console.log(y + ' ' + x);
if(grid[y-1]){
if(grid[y-1][x] === 0) {
grid[y-1][x] = 4;
recursiveSearch(y-1, x);
}
if(grid[y-1][x] === 2) {
console.log('inside return if');
return 'end point found at';
}
}
if(grid[y][x+1] || grid[y][x+1] === 0) {
if(grid[y][x+1] === 0) {
grid[y][x+1] = 4;
recursiveSearch(y,x+1);
}
if(grid[y][x+1] === 2) {
return "end point found at";
}
}
if(grid[y+1] || grid[y+1] === 0) {
if(grid[y+1][x] === 0) {
grid[y+1][x] = 4;
recursiveSearch(y+1,x);
}
if(grid[y+1][x] === 2) {
return "end point found at";
}
}
if(grid[y][x-1] || grid[y][x-1] === 0 ) {
if(grid[y][x-1] === 0) {
grid[y][x-1] = 4;
recursiveSearch(y,x-1);
};
if(grid[y][x-1] === 2) {
return "end point found at";
}
} else {
return "No solution found"
}
};
you must return value of calling recursive function.
const grid =[0,0,0,0,3,2],
[0,0,0,0,3,0],
[0,0,0,0,3,0],
[3,3,3,3,3,0],
[0,0,0,0,0,0],
[1,3,3,3,3,3]
],
const recursiveSearch = (y, x) => { // init values y=5 x=0
console.log(y + ' ' + x);
if(grid[y-1]){
if(grid[y-1][x] === 0) {
grid[y-1][x] = 4;
return recursiveSearch(y-1, x); // must return value of calling recursiveSearch
}
if(grid[y-1][x] === 2) {
console.log('inside return if');
return 'end point found at';
}
}
if(grid[y][x+1] || grid[y][x+1] === 0) {
if(grid[y][x+1] === 0) {
grid[y][x+1] = 4;
return recursiveSearch(y,x+1); // // must return value of calling recursiveSearch
}
if(grid[y][x+1] === 2) {
return "end point found at";
}
}
if(grid[y+1] || grid[y+1] === 0) {
if(grid[y+1][x] === 0) {
grid[y+1][x] = 4;
return recursiveSearch(y+1,x); // must return value of calling recursiveSearch
}
if(grid[y+1][x] === 2) {
return "end point found at";
}
}
if(grid[y][x-1] || grid[y][x-1] === 0 ) {
if(grid[y][x-1] === 0) {
grid[y][x-1] = 4;
return recursiveSearch(y,x-1); // must return value of calling recursiveSearch
};
if(grid[y][x-1] === 2) {
return "end point found at";
}
} else {
return "No solution found"
}
};
Kindly add return statement for every recursive call.
I have 2 large objects to compare. I want to know if they are equal.
JSON.stringify(obj1) == JSON.stringify(obj2) does not work, because the objects are dynamically created so the order of the attributes are random.
So I wrote a isEqual() as follows.
function isEqual(ar1, ar2) {
if(ar1 !== ar2) {
if(typeof ar1 !== typeof ar2) {
return false;
}
if(ar1 == null) {
if(ar2 == null) {
return true;
}
return false;
}
if(ar2 == null) {
if(ar1 == null) {
return true;
}
return false;
}
if(typeof ar1 !== 'object') {
return false;
}
if (ar1.length !== ar2.length) {
return false;
}
for(var i in ar1) {
if(!isEqual(ar1[i], ar2[i])) {
return false;
}
}
for(var i in ar2) {
if(!isEqual(ar1[i], ar2[i])) {
return false;
}
}
}
return true;
}
Now if I run isEqual(obj1, obj2) the tab in chrome freezes and I am not able to close the tab. I have to wait until chrome asks me to close non responding tabs after about 10 minutes. How to solve this?
Use Lodash's isEqual to do this for you.
https://lodash.com/docs/4.17.4#isEqual
I'd like to offer my solution. Please try it with your JSON objects.
in order to check if objects have a different number of fields you can use
Object.keys(ar1).length !== Object.keys(ar2).length
function isEqual(ar1, ar2) {
if((ar1 === null) && (ar2 === null))
return true;
//console.info("Type: " + typeof ar1 + ":" + typeof ar2)
if (typeof ar1 !== typeof ar2) {
return false;
}
console.info("Length: " + ar1.length + ":" + ar2.length)
if (ar1.length !== ar2.length) {
return false;
}
if((typeof ar1 === 'object') && (typeof ar2 === 'object') && (Object.keys(ar1).length !== Object.keys(ar2).length))
return false;
if ((typeof ar1 !== 'object') && (typeof ar2 !== 'object')) {
//console.info("Value is not equal: " + (ar1 !== ar2))
if (ar1 !== ar2)
return false;
else
return true;
}
for (var i in ar1) {
//console.info("Values:" + ar1[i] + ":" + ar2[i])
if (!isEqual(ar1[i], ar2[i])) {
return false;
}
}
return true;
}
var obj1 = {
a : 1,
b :[1, 2, 3],
c: {a:1}
};
var obj2 = {
a : 1,
b : [1, 2, 3],
c: {a:1},
d:1
};
isEqual(obj1, obj2)
Hey so i'm writing a function that checks whether a series of braces is a valid sequence. I have the following code, which mostly does what I want it to do, except it it always returns false. If i enter a valid sequence of braces it ends up in the right if-statement, but never returns true. I don't understand why.
function match(s) {
if (s === '(') {
return ')'
}
else if (s === '[') {
return ']'
}
else if (s === '{') {
return '}'
}
}
function open(b) {
if ( (b === '(' ) || (b === '[' ) || (b === '{') ) {
return true;
}
return false;
}
function checkValid(string, temp, n) {
var current = string.charAt(n)
var currentMatch = temp.charAt(0)
if (!(current) && (n === string.length) && (temp === "")) {
console.log('hey')
return true
}
if (open(current)) {
temp = match(current).concat(temp)
checkValid(string, temp, n+1)
}
else {
if (current === currentMatch) {
temp = temp.substr(1)
checkValid(string, temp, n+1)
}
return false;
}
return false;
}
function validBraces(braces) {
var n = 0
var temp = ''
return checkValid(braces, temp, n)
}
validBraces('()') // should return true
validBraces('[[)}}{') //should return false
The last return false is always being returned from your original checkValid function call.
This is because you aren't returning the recursive checkValid calls.
function match(s) {
if (s === '(') {
return ')'
}
else if (s === '[') {
return ']'
}
else if (s === '{') {
return '}'
}
}
function open(b) {
if ( (b === '(' ) || (b === '[' ) || (b === '{') ) {
return true;
}
return false;
}
function checkValid(string, temp, n) {
var current = string.charAt(n)
var currentMatch = temp.charAt(0)
if (!(current) && (n === string.length) && (temp === "")) {
console.log('hey')
return true
}
if (open(current)) {
temp = match(current).concat(temp)
return checkValid(string, temp, n+1)
}
else {
if (current === currentMatch) {
temp = temp.substr(1)
return checkValid(string, temp, n+1)
}
return false;
}
return false;
}
function validBraces(braces) {
var n = 0
var temp = ''
return checkValid(braces, temp, n)
}
validBraces('()') // should return true
validBraces('[[)}}{') //should return false
I currently have this code built in JS, but it's really, really ugly.
Is there any better way to approach it?
The way it works basically is pushing a string like app.chat.test to be the key, and value like teststr.
I test the lengths to see if the "parent" key is there, otherwise we build it.
function constructJson(jsonKey, jsonValue){
//REWRITE!!!!!!!!
let jsonObj = langFile;
let jsonKeyArr = jsonKey.split('.')
if (jsonKeyArr.length === 1) {
if (valToAdd === undefined) {
if (jsonObj[jsonKey] === undefined) {
jsonObj[jsonKey] = {}
}
} else {
if (jsonObj[jsonKey] === undefined) {
jsonObj[jsonKey] = valToAdd
}
}
} else if (jsonKeyArr.length === 2) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = jsonValue
}
} else if (jsonKeyArr.length === 3) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = jsonValue
}
} else if (jsonKeyArr.length === 4) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] = jsonValue
}
} else if (jsonKeyArr.length === 5) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]][jsonKeyArr[4]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]][jsonKeyArr[4]] = jsonValue
}
} else if (jsonKeyArr.length > 5) {
return console.log("Length over 5 not supported yet!")
}
return jsonObj;
}
Regards.
OF course it's possible, a simple loop will perfeclty do the job.
function constructJson(jsonKey, jsonValue){
//REWRITE!!!!!!!!
langFile = {a:{}, foo:{}};// remove this for your own code
var jsonObj = langFile;
var jsonKeyArr = jsonKey.split('.');
var currentValue = jsonObj;
for(var i = 0; i < jsonKeyArr.length;i++){
if(currentValue[jsonKeyArr[i]]===undefined){
currentValue[jsonKeyArr[i]] = {};
}
if(i < jsonKeyArr.length-1){
currentValue = currentValue[jsonKeyArr[i]];
}else{
currentValue[jsonKeyArr[i]] = jsonValue;
}
}
return jsonObj;
}
alert(JSON.stringify(constructJson("a.b.cd.ef", "toto")));
I just assigning to a temporary variable each sublevel. When i'm on the last i'm assigning the value.
Yes you can, using the javascript reduce function on the array created from the splitted string.
function namespaceCreateExceptLast(representationOfElementToCreate, baseNamespace) {
var tokens;
if (typeof representationOfElementToCreate !== 'string')
throw new Error('Expecting string as first parameter');
if (baseNamespace === undefined)
baseNamespace = window;
tokens = representationOfElementToCreate.split('.');
// Remove the last element (which will contain the value)
tokens.pop();
// Use reduce to create part by part your new object
return tokens.reduce(function (prev, property) {
if (typeof prev !== 'object') {
throw Error('One property is already defined but not an object, namespace creation has failed', property);
return undefined;
} else {
if (!prev[property])
prev[property] = {};
return prev[property];
}
}, baseNamespace);
};
Then you can have:
function constructJson(jsonKey, jsonValue){
let jsonObj = langFile;
var lastItem = namespaceCreateExceptLast(jsonKey, jsonObj);
var lastKey = jsonKey.substring(jsonKey.lastIndexOf('.') + 1);
lastItem[lastKey] = jsonValue;
}
I have added some comments and exceptions to help you understand how it's done, but it's mainly based on the reduce function which you can easily get help for (https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce).
I'm getting a "Maximum call stack size exceeded." while trying to iterate the contents of an array and I can't for the life of me figure out why
Edit: By the way I want to add that this is for Safari
here's the function:
function compareObj(a,b) {
var u = function(c,d) {//Check types
var type = Object.prototype.toString.call(a)
if (type !== Object.prototype.toString.call(b)) return false
return type.slice(8,-1) == 'Array' ? v(a,b) : type.slice(8,-1) == 'Object' ? w(a,b) :
type.slice(8,-1) == 'String' ? x(a,b) : type.slice(8,-1) == 'Number' ? y(a,b) :
type.slice(8,-1) == 'Boolean' ? z(a,b) : false ;
}
var v = function(c,d) {//Array
if (c.length !== d.length) return false
/*for (var i = 0; i < c.length; i++) {
if (!u(c[i],d[i])) {
return false
}
}*/
while (c.length) {
if (!u(c[0],d[0])) {
return false
} else {
c.shift();
d.shift();
}
}
return true
}
var w = function(c,d) {//Object
for (i in c) {
}
return true
}
var x = function(c,d) {//String
return c === d
}
var y = function(c,d) {//Number
return c === d
}
var z = function(c,d) {//Boolean
return c === d
}
return u(a,b)
}
I get the overload in the return statement of the u() function
Your function can be a lot shorter. It's advisable to use meaningfull function names. Some functions are redundant. There is no need for recursion. I took the liberty to rewrite your function, just for demonstration. You can see it in action here.
function compareObj(a,b) {
var doCompare = function(c,d) {
//Check types (IE compatible)
var objRE = /Array|Object|String|Number|Boolean/,
aType = a.constructor.name || String(a.constructor).match(objRE)[0],
bType = b.constructor.name || String(b.constructor).match(objRE)[0];
//Types different? No dice.
if (aType !== bType) {return false;}
switch(aType){
case 'Array' : return arrayCompare(a,b); break;
case 'Object' : return objectCompare(a,b); break;
case 'String' : return valueCompare(a,b); break;
case 'Number' : return valueCompare(a,b); break;
case 'Boolean': return valueCompare(a,b); break;
default: return false
}
}
var arrayCompare = function(c,d) { //Array
if (c.length !== d.length) {return false;}
var i = c.length;
while (--i) {
if ( !valueCompare(c[i],d[i]) ) {
return false;
}
}
return true;
}
var objectCompare = function(c,d) { //Object
//you'll have to consider the number of elements too
var lenb = 0, lena = 0;
for (var label in d){
if (d.hasOwnProperty(label)) { lenb+=1; }
}
for (var label in c) {
if (c.hasOwnProperty(label)){
lena += 1;
if ( !valueCompare(c[label],d[label]) ) {
return false;
}
}
}
return lena === lenb;
}
var valueCompare = function(c,d) {//String
return JSON.stringify(c) === JSON.stringify(d);
}
return doCompare(a,b);
}
Actually, if you use JSON (native in newer browsers, or from library), you can do all this just using:
function compare(a,b){
return JSON.stringify(a) === JSON.stringify(b);
}