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);
}
Related
This code return "false" for test input "1" only when I submit in leet code. It's working when I do it in my local or leet code editor for the same input
var temp = 0;
var rev = 0;
var palindromeCheck = function (org) {
temp = org % 10;
rev = rev * 10 + temp;
org = parseInt(org / 10);
if (org > 0) {
palindromeCheck(org);
}
return rev;
};
var isPalindrome = function (x) {
if (x == 0) {
return true;
}
else if(x > 0) {
var value = palindromeCheck(x);
if (value === x) {
return true;
}
else {
return false;
}
}
else {
return false;
}
};
your palindromeCheck() function return a number. The problem comes from this part, where you strictly compare a number and a string:
if (value === x) {
return true;
}
else {
return false;
}
try to do :
if (value == x) {
return true;
}
else {
return false;
}
or
return (value == x);
else you can just use parseInt() function.
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'm trying to simplify this function, as there can be multiple type of data objcts and for each type there is also a male and a female version.
The number and name of the elements in the objects are always identical.
As you see, most of the code is repeating...
function calculate(type, j, value, s) {
for (var i = j; i > 4; i--) {
if (type == 'weight') {
if (s == 'f') {
if (weightFemale.hasOwnProperty(i)) {
var m = weightFemale[i][0],
l = weightFemale[i][1],
s = weightFemale[i][2];
return getcalc( m,l,s );
}
}
else {
if (weightMale.hasOwnProperty(i)) {
var m = weightMale[i][0],
l = weightMale[i][1],
s = weightMale[i][2];
return getcalc( m,l,s );
}
}
}
else if (type == 'length') {
if (s == 'f') {
if (lengthFemale.hasOwnProperty(i)) {
var m = lengthFemale[i][0],
l = lengthFemale[i][1],
s = lengthFemale[i][2],
return getcalc( m,l,s );
}
}
else {
if (lengthMale.hasOwnProperty(i)) {
var m = lengthMale[i][0],
l = lengthMale[i][1],
s = lengthMale[i][2],
return getcalc( m,l,s );
}
}
}
}
return false;
}
How can I simplify the if/else-parts for the type and the sex?
Since you are doing the same thing to each object , just make your conditionals define a single object reference and only call calculation once.
Something like:
var obj;
if (type == 'weight') {
obj = s == 'f' ? weightFemale : weightMale;
} else if (type == 'length') {
obj = s == 'f' ? lengthFemale : lengthMale;
}
if (obj.hasOwnProperty(i)) {
var m = obj[i][0],
l = obj[i][1],
s = obj[i][2];
return getcalc(m, l, s);
}
I would create a own function and create a switch
switch(type) {
case "weight":
getValues();
break;
case "length":
getValues();
break;
}
Ask yourself, what are the parts that are very similar? It looks if .hasOwnProperty() is true, you get m, l, and s from the array and then call getcalc(). Start by extracting that part into a function with the differing pieces being passed in as parameters.
Another pattern is that you're using a particular array based on certain conditions. Getting the array you want can be placed into a function.
Also, not quite related to the question, but you may want to give your variables better names. This makes the code more readable and easier to reason about.
Here's what I came up with:
function getArray(type, s){
if(type == 'weight') {
return s == 'f' ? weightFemale : weightMale;
}
else if(type == 'length') {
return s == 'm' ? lengthFemale : lengthMale;
}
}
function makeCalculation(array, i) {
if(array.hasOwnProperty(i)) {
var m = lengthMale[i][0],
l = lengthMale[i][1],
s = lengthMale[i][2],
return getcalc( m,l,s );
}
}
function calculate(type, j, value, s) {
for (var i = j; i > 4; i--) {
var array = getArray(type, s);
return makeCalculation(array, i);
}
}
Firstly you can create function like this:
function _getcalc(arr, i) {
var m = arr[i][0],
l = arr[i][1],
s = arr[i][2];
return getcalc(m, l, s);
}
Then you can shorten your function like this:
function calculate(type, j, value, s) {
for (var i = j; i > 4; i--) {
switch(type) {
case 'weight':
if (s == 'f' && weightFemale.hasOwnProperty(i)) {
return _getcalc(weightFemale, i);
} else if(weightMale.hasOwnProperty(i)) {
return _getcalc(weightMale, i);
}
break;
case 'length':
if (s == 'f' && lengthFemale.hasOwnProperty(i)) {
return _getcalc(lengthFemale, i);
} else if(lengthMale.hasOwnProperty(i)) {
return _getcalc(lengthMale, i);
}
break;
}
}
return false;
}
Working on a Holdem hand evaluator, and part of the yak shaving is writing a "how many combos of 5 do you get from 7 cards" function (pickNofSet()). I've done that, but the way I've done that returns a bunch of duplicates.
So I have to write a removeDuplicates(). Here's the problem... it works with a simple array, but it doesn't work with the "arrays of arrays" that my "pickNofSet" function generates.
-- here's the removeDuplicates code --
var removeDuplicates = function(input){ // takes array
var output = [];
for (i=0; i < input.length; i++){
var unique = true; // all elements are innocent until proven guilty
for(j=i+1; j < input.length; j++){
if(input[j] === input[i]){
unique = false; // guilty!
};// endif
};// end jfor
if(unique){ // if not found guilty,
output.push(input[i]); // you may go free, little element
};// end if
};// end ifor
console.log(output);
return output; };//end function
Here's what I get from the Console:
> removeDuplicates(['a','b','c'],['a','b','c'],['d','e','f'],['g','h','i']);
< undefined
> removeDuplicates([1, 2, 2, 3, 3, 5, 5, 6, 6, 6]);
< [1, 2, 3, 5, 6]
Operator === can't compare array
As you use === to check equality between two elements, this only works with primitive data types, but not array. e.g.
1===1 // true
[1]===[1] // Sorry, you can't
If you want your algorithm to work with both primitive elements and array elements, you may need to upgrade your equality check from === to a customized function.
From this:
if(input[j] === input[i]){
unique = false; // guilty!
};// endif
To this:
if (equals(input[j],input[i]){
unique = false; // guilty!
};// endif
And implement equals function to be capable of comparing both primitive data types and arrays:
function equals(a,b){
if (typeof(a)!=typeof(b))
return false;
else if (typeof(a)=='object'){
if (Object.keys(a).length != Object.keys(b).length)
return false;
else{
for (var keyA of Object.keys(a)){
if (!(keyA in b))
return false;
else if (a[keyA]!==b[keyA])
return false;
else
return true;
}
}
}
else
return a===b;
}
Hint: This solution should, hopefully, also work with JSON element.
Here is an example of a general purpose unique filter that should fill your need. Requires an ES5 compliant environment.
(function () {
'use strict';
function $strictEqual(a, b) {
return a === b;
}
function $isUndefined(inputArg) {
return $strictEqual(typeof inputArg, 'undefined');
}
function $isPrimitive(inputArg) {
var type = typeof inputArg;
return type === 'undefined' || inputArg === null || type === 'boolean' || type === 'string' || type === 'number' || type === 'symbol';
}
function $isFunction(inputArg) {
return typeof inputArg === 'function';
}
function $isDate(inputArg) {
return Object.prototype.toString.call(inputArg) === '[object Date]';
}
function $isRegExp(inputArg) {
return Object.prototype.toString.call(inputArg) === '[object RegExp]';
}
function $isString(inputArg) {
return Object.prototype.toString.call(inputArg) === '[object String]';
}
function $isArguments(inputArg) {
return Object.prototype.toString.call(inputArg) === '[object Arguments]';
}
function $getItem(object, index) {
var item;
if ($isString(object)) {
item = object.charAt(index);
} else {
item = object[index];
}
return item;
}
var de = function (a, b, circ) {
if (a === b) {
return true;
}
var aType,
bType,
aIsArgs,
bIsArgs,
aIsPrim,
bIsPrim,
aCirc,
bCirc,
ka,
kb,
length,
index,
it;
if ($isDate(a) && $isDate(b)) {
return a.getTime() === b.getTime();
}
if ($isRegExp(a) && $isRegExp(b)) {
return a.source === b.source &&
a.global === b.global &&
a.multiline === b.multiline &&
a.lastIndex === b.lastIndex &&
a.ignoreCase === b.ignoreCase &&
a.sticky === b.sticky;
}
aIsPrim = $isPrimitive(a);
bIsPrim = $isPrimitive(b);
if ((aIsPrim || $isFunction(a)) && (bIsPrim || $isFunction(b))) {
/*jslint eqeq: true */
return a == b;
}
if (aIsPrim || bIsPrim) {
return a === b;
}
if (a.prototype !== b.prototype) {
return false;
}
if (circ.a.indexOf(a) === -1) {
circ.a.push(a);
} else {
aCirc = true;
}
if (circ.b.indexOf(b) === -1) {
circ.b.push(b);
} else {
bCirc = true;
}
if (aCirc && bCirc) {
circ.cnt += 1;
} else {
circ.cnt = 0;
}
if (circ.cnt > 200) {
throw new RangeError('Circular reference limit exceeded');
}
aIsArgs = $isArguments(a);
bIsArgs = $isArguments(b);
if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) {
return false;
}
if (aIsArgs) {
return de(Array.prototype.slice.call(a), Array.prototype.slice.call(b), circ);
}
ka = Object.keys(a);
kb = Object.keys(b);
length = ka.length;
if (length !== kb.length) {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) {
return false;
}
} else {
return false;
}
} else {
ka.sort();
kb.sort();
for (index = 0; index < length; index += 1) {
if (ka[index] !== kb[index]) {
return false;
}
}
}
for (index = 0; index < length; index += 1) {
it = ka[index];
if (!de($getItem(a, it), $getItem(b, it), circ)) {
return false;
}
}
aType = typeof a;
bType = typeof b;
return aType === bType;
};
if (!Object.prototype.deepEqual) {
Object.defineProperty(Object.prototype, 'deepEqual', {
enumerable: false,
configurable: true,
writable: true,
value: function (b) {
var a = this;
return de(a, b, {
a: [],
b: [],
cnt: 0
});
}
});
}
if (!Array.prototype.unique) {
Object.defineProperty(Array.prototype, 'unique', {
enumerable: false,
configurable: true,
writable: true,
value: function (equalFn, thisArg) {
var object = Object(this),
length,
index,
eqFn,
arr,
idx,
val,
it;
if ($isUndefined(equalFn)) {
eqFn = $strictEqual;
} else {
eqFn = equalFn;
}
if (!$isFunction(eqFn)) {
throw new TypeError('Argument is not a function: ' + eqFn);
}
arr = [];
length = object.length >>> 0;
for (index = 0; index < length; index += 1) {
if (index in object) {
it = $getItem(object, index);
val = true;
for (idx = 0; idx < length; idx += 1) {
if (idx < index && idx in object && eqFn.call(thisArg, it, $getItem(object, idx))) {
val = false;
break;
}
}
if (val) {
arr.push(it);
}
}
}
return arr;
}
});
}
}());
var data1 = [1, 2, 2, 3, 3, 5, 5, 6, 6, 6],
data2 = [
['a', 'b', 'c'],
['a', 'b', 'c'],
['d', 'e', 'f'],
['g', 'h', 'i']
],
equals = Function.prototype.call.bind(Object.prototype.deepEqual),
pre = document.getElementById('out');
pre.textContent = JSON.stringify(data1.unique(equals), null, 2);
pre.textContent += '\n\n';
pre.textContent += JSON.stringify(data2.unique(equals), null, 2);
<pre id="out"></pre>
I always need to deal with multi-level js objects where existence of properties are not certain:
try { value1 = obj.a.b.c; } catch(e) { value1 = 1; }
try { value2 = obj.d.e.f; } catch(e) { value2 = 2; }
......
Is there an easier way or a generic function (e.g. ifnull(obj.d.e.f, 2) ) that does not require a lot of try catches?
var value1 = (obj.a && obj.a.b && obj.a.b.c) || 1;
http://jsfiddle.net/DerekL/UfJEQ/
Or use this:
function ifNull(obj, key, defVal){
var keys = key.split("."), value;
for(var i = 0; i < keys.length; i++){
if(typeof obj[keys[i]] !== "undefined"){
value = obj = obj[keys[i]];
}else{
return defVal;
}
}
return value;
}
var value1 = ifNull(obj, "a.b.c", 1);
You could always create a helper function.
function isUndefined(root, path, defaultVal) {
var parts = path.split('.'),
i = 0,
len = parts.length,
o = root || {}, v;
while ((typeof (v = o[parts[i]]) === 'object', o = v) && ++i < len);
return (typeof v === 'undefined' || i !== len)? defaultVal: v;
}
var obj = {a: { b: { test: 'test' }}}, v;
v = isUndefined(obj, 'a.b.test', 1); //test
v = isUndefined(obj, 'a.test', 1); //1
Using lodash you can do this easily**(node exists and empty check for that node)**..
var lodash = require('lodash-contrib');
function invalidateRequest(obj, param) {
var valid = true;
param.forEach(function(val) {
if(!lodash.hasPath(obj, val)) {
valid = false;
} else {
if(lodash.getPath(obj, val) == null || lodash.getPath(obj, val) == undefined || lodash.getPath(obj, val) == '') {
valid = false;
}
}
});
return valid;
}
Usage:
leaveDetails = {
"startDay": 1414998000000,
"endDay": 1415084400000,
"test": { "test1" : 1234 }
};
var validate;
validate = invalidateRequest(leaveDetails, ['startDay', 'endDay', 'test.test1']);
it will return boolean.