I wrote a simple function checking if an array contains duplicates, I want it to return true if it does and false if it doesn't.
function containsDuplicates(a) {
var hash = {};
a.forEach((elem, index) => {
if (hash[elem] === undefined) {
hash[elem] = 1;
} else {
console.log('true')
return true;
}
if (index === a.length - 1) {
console.log('false')
return false;
}
})
}
var arr = [1, 2, 3, 4];
containsDuplicates(arr)
My console.log logs just fine but it doesn't seem to be hitting the return. My entire function returns undefined every time. Why is this the case?
You are returning from the callback that you passed to forEach().
You are returning from the callback you passed to foreach. You should try something like this instead.
function hasDuplicates(array) {
var keyStore = {};
for (var i = 0; i < array.length; ++i) {
var value = array[i];
if (value in keyStore) {
return true;
}
keyStore[value] = true;
}
return false;
}
Related
The following code is failing when I call it with isValid("()"). When I debugged it, I see that the comparision fails at parantheses[parantheses.length - 1] === p even though both the values are same. Can anyone tell why this is failing ?
var isValid = function(s) {
const openParantheses = new Set("(", "{", "[");
const closedParantheses = new Set(")", "}", "]");
const parantheses = [];
for (let p of s) {
if (openParantheses.has(p)) {
parantheses.push(p);
} else if (closedParantheses.has(p)) {
if (parantheses[parantheses.length - 1] === p) {
parantheses.pop();
} else {
return false;
}
}
}
if (parantheses.length > 0) {
return false;
}
return true;
};
console.log(isValid("()"))
Also when I do console.log(Inside If - ${parantheses}) This isnt printing the parantheses array as an array but just giving out values without array notation. Is this something expected ?
Thanks.
Since you never add closed parentheses to the array, the parantheses[parantheses.length - 1] === p clause is never true.
I would advise mapping closed parentheses to open ones and using this map to perform your check as I have done below.
Another thing: The Constructor of Set takes an array (or any iterable) of values. (source)
var isValid = function(testString) {
const openParantheses = new Set([
"(",
"{",
"["
]);
const closedParantheses = new Map([
[')', '('],
[']', '['],
['}', '{'],
]);
const parantheses = [];
for (const character of testString) {
if (openParantheses.has(character)) {
parantheses.push(character);
continue;
}
if (closedParantheses.has(character)) {
if (parantheses[parantheses.length - 1] === closedParantheses.get(character)) {
parantheses.pop();
continue;
}
return false;
}
}
return parantheses.length === 0;
};
console.log(isValid("()"));
console.log(isValid("[]"));
console.log(isValid("{}"));
console.log(isValid("([{}])"));
console.log(isValid("({[}])"));
var isValid = function(s) {
const openParantheses = "({[";
const closedParantheses = ")}]";
const parantheses = [];
for (let p of s) {
if (openParantheses.indexOf(p) >= 0) {
parantheses.push(p);
} else if (closedParantheses.indexOf(p) >= 0) {
if (openParantheses.indexOf(parantheses[parantheses.length - 1]) ===
closedParantheses.indexOf(p)) {
parantheses.pop();
} else {
return false;
}
}
}
if (parantheses.length > 0) {
return false;
}
return true;
};
console.log(isValid("()"))
function each(collection, callback) {
var arr = [];
for(var i = 0; i < collection.length; i++) {
var result = callback(collection[i])
if (typeof result !== 'undefined') {
arr.push(callback(collection[i]));
}
}
return arr
}
function isNumber(item) {
if (typeof item === "number") {
return item * 2;
}
}
I am trying to understand higher order functions. The above works, but is apparently not best practice to return a value with isNumber. I have been told that a Boolean value should be returned. Why? It works.
Update:
It appears to be because of the function name! Thanks everyone I just thought there might be some technical reason
If a function is called isNumber, it should return a boolean.
Also, your each function is a map not an each. In that case your code should probably look like.
function flatMap(collection, callback) {
var arr = [];
for(var i = 0; i < collection.length; i++) {
var result = callback(collection[i])
if (typeof result !== 'undefined') {
arr.push(callback(collection[i]));
}
}
return arr;
}
function times2(item) {
if (typeof item === "number") {
return item * 2;
}
return item;
}
map([1,2,3,"hello"], times2);
If you wanted iteration that can be stopped, then it would look like
function iterate(collection, callback) {
for(var i = 0; i < collection.length; i++) {
var result = callback(collection[i])
if (typeof result === false) {
return;
}
}
}
function doSomethingAndStopIfNotANumber(item) {
console.log(item);
return typeof item == "number";
}
iterate([1,2,3, "hello", 4, 5], doSomethingAndStopIfNotANumber);
Note that Array.prototype.forEach does not allow you to stop iteration by returning false, for that you'd need to misuse Array.prototype.every (because that function returns a boolean, so it's just a semantic problem, not like map where you build an array and throw it away) or write a function like I did above.
I've the following implementation.
Array.prototype.abc = function(condition, t){
var arr = [];
for( var i = 0; i < this.length; i++){
arr.push(condition(this[i],t));
}
return arr;
};
var a = [1,2,3,4];
var t = 2;
alert(a.abc( function(item,diviser){
if(item % diviser === 0) { return item; }
},t));
The result should be [2,4]. Instead I'm getting [,2,,4].
I've tried the following conditions but it always returns the above result.
if(condition(this[i],t) !== false){ arr.push(condition(this[i],t)); }
This I'm doing when I do
if(item % diviser === 0) { return item; } else { return false; }
The false condition doesnot work for 'false' or true or 'true' or for that matter any value I return in else part. In the actual implementation I do not have the else part though. I know we can use splice or something to remove the blank sections. But I do not understand even if i don't return anything why blank in being created. And even after using if condition before arr.push it does not work. What exactly is happening and how to remove the blanks in the array?
You have to check whether the returned value is undefined or not from your callBack,
for( var i = 0; i < this.length; i++){
var x = condition(this[i],t);
if(typeof x !== "undefined") arr.push(x);
}
You have made 2 different attempts to fix this but that will fail because,
!== false, your callBack will return either a number or undefined. So the strict equality will fails all the time and will be evaluated to false always since the operand's types are different.
if(item % diviser === 0) { return item; } else { return false; } This will return false when the condition fails and hence false will be pushed into the array. And it will not skip that pushing part.
Move the cmondition outside of the push and place it before. The condition should only return true or false.
condition(this[i],t) && arr.push(this[i]);
This is because you are doing a push regardless of what condition is returning.
Replace this
arr.push(condition(this[i],t));
with
var val = condition(this[i],t)
val = val !== false && arr.push(val);
Since your condition method is explicitly returing false, you can simply check for val !== false
DEMO
Array.prototype.abc = function(condition, t){
var arr = [];
for( var i = 0; i < this.length; i++){
var val = condition(this[i],t); console.log(val);
val !== false && arr.push(val);
}
return arr;
};
var a = [1,2,3,4];
var t = 2;
document.body.innerHTML += a.abc( function(item,diviser){
if(item % diviser === 0) { return item; } else { return false; }
},t);
In a regular function, I can use the same result array in each iteration:
_.unique = function(array) {
var result = [];
for (var i = 0; i < array.length; i++) {
if (result.indexOf(array[i]) < 0) {
result.push(array[i]);
}
}
return result;
};
How can I do the same (and keep pushing to my result array) when working with a recursive function?
_.unique = function(array) {
var result = [];
if (array.length === 0) {
return result;
} else {
if (result.indexOf(array[0]) < 0) {
result.push(array[0]);
}
return _.unique(array.slice(1));
}
return result;
};
Using this, I'm getting the wrong outputs. I can do this using a inside helper function, but I prefer not to.
You must, pass the result to another function so the called function knows if the item is unique. In the following code example, the array of unique items is passed with the name p_result.
This is a working code example:
_.unique = function(array, p_result) {
if(!(Object.prototype.toString.call(p_result) == '[object Array]')) p_result = [];
var result = p_result;
if(array.length === 0) return result;
if(p_result.indexOf(array[0]) < 0) {
result.push(array[0]);
}
return _.unique(array.slice(1), result);
};
// e.g. _.unique([0, 1, 1, 2, 3, 7, 4]) gives [0, 1, 2, 3, 7, 4]
Example fiddle that uses the code above
When I call this with [1,2,3,4], it returns undefined and I'm not understanding why. The goal is for it to return true if any combination of numbers in the array add up to the maximum number in the array, and false if it's not possible.
function ArrayAdditionI(arr) {
var max = Math.max.apply(null, arr);
arr.splice(arr.indexOf(max), 1);
var sum = function(arr) { return arr.reduce(function(a,b) { return a + b; }); };
function combos(arr) {
var f = function(prefix, arr) {
for (var i = 0; i < arr.length; i++) {
var clone = prefix.slice(0);
clone.push(arr[i]);
if (sum(clone) == max) { return true; }
return f(clone, arr.slice(i+1));
}
}
return f([], arr);
}
return combos(arr);
}
f is returning undefined when it is called with an empty arr! You will need to explicitly return false if none of the tests in the loop returned from the function. And you must not return false on the first occasion of the loop, but break only when you found true and continue the loop elsewhile.
To fix this, you'd have something like
function combos(arr) {
function f(prefix, arr) {
for (var i = 0; i < arr.length; i++) {
var clone = prefix.slice(0);
clone.push(arr[i]);
if (sum(clone) == max) return true;
if (f(clone, arr.slice(i+1))) return true;
}
return false;
}
return f([], arr);
}
However, also your recursion scheme with the loop looks a bit complicated. I would rather go with the naive enumeration of the "binary tree", where the nodes of each level decide whether the current item will be included in the to-be-tested subset:
function ArrayAdditionI(arr) {
var max = Math.max.apply(null, arr);
arr.splice(arr.indexOf(max), 1);
var sum = function(arr) { return arr.reduce(function(a,b) { return a + b; }, 0); };
function f(subset, arr) {
return arr.length
? f(subset, arr.slice(1)) || f(subset.concat([arr[0]]), arr.slice(1))
: sum(subset) == max
}
return f([], arr);
}
It seems that you don't test all the possible combination.
Here you will test 1+2+3, 2+3, 3 but never 1+3.
Do you really want to have a recursive function here ?
There may be some more simple way to find that.
function ArrayAdditionI(arr) {
var max = Math.max.apply(null, arr);
arr.splice(arr.indexOf(max), 1);
var res = arr.filter(function(num, idx) {
var combination = false;
// Check all combination non previously tested
for (var i = idx; i < arr.length - 1; i++) {
if (num + arr[i+1] === max) {
combination = true;
break;
}
}
return combination;
});
return res.length > 0;
}
The problem is your f function is not ever hitting the
if (sum(clone) == max) { return true; }
line of code so it will just keep recursively calling until arr.length == 0 and it will return undefined.
Your variables torf and results are unused, maybe you forgot to do something with them?