How to stop a recursive function? - javascript

So I have this code for my discord bot. It is suppose to check if the input entered by user is correct or not. Based on that run the command again by itself. I did it using recursive function. It works as long as user inputs correct string. But i want it to run only three times.
//Code
function recurssiveShit() {
var arr = [];
var i;
let hackString = "";
//create a unique 4 digits array
while (arr.length < 4) {
var r = Math.floor(Math.random() * 9) + 1;
if (arr.indexOf(r) === -1) arr.push(r);
}
console.log(arr);
//show the array to be sorted
message.channel.send("Write it in increasing order.\n" +
`\`${arr[0]},${arr[1]},${arr[2]},${arr[3]},\``);
//sort the array in increasing order
arr.sort((a, b) => a - b);
//store the sorted array as string
for (i = 0; i < 4; i++) {
hackString += arr[i];
}
//check is user's input is same as sorted array
message.channel.awaitMessages(filter, { max: 1, time: 6000 }).then(collected => {
let check = collected.first().content;
if (check === hackString) {
message.channel.send("Hack Successful");
recurssiveShit();
}
else {
return message.channel.send("Incorrect");
}
}).catch(err => {
console.log("Time ran out");
})
console.log(hackString);
}
recurssiveShit();

You could create a variable outside the function, increment it when needed, and check that it hasn't exceeded its limit before recursively firing another function.
var count = 0;
function recurssiveShit() {
var arr = [];
var i;
let hackString = '';
//create a unique 4 digits array
while (arr.length < 4) {
var r = Math.floor(Math.random() * 9) + 1;
if (arr.indexOf(r) === -1) arr.push(r);
}
console.log(arr);
//show the array to be sorted
message.channel.send(
'Write it in increasing order.\n' +
`\`${arr[0]},${arr[1]},${arr[2]},${arr[3]},\``
);
//sort the array in increasing order
arr.sort((a, b) => a - b);
//store the sorted array as string
for (i = 0; i < 4; i++) {
hackString += arr[i];
}
//check is user's input is same as sorted array
message.channel
.awaitMessages(filter, { max: 1, time: 6000 })
.then((collected) => {
let check = collected.first().content;
if (check === hackString) {
message.channel.send('Hack Successful');
if (++count !== 3) { // increment counter, than check if it equals three
recurssiveShit();
} else {
// code...
}
} else {
return message.channel.send('Incorrect');
}
})
.catch((err) => {
console.log('Time ran out');
});
console.log(hackString);
}
recurssiveShit();

Related

Get permutations of all the array [1, 1, 1, 1, 1, 0, 0, 0, 0]

I am trying to create a script which generates all the various permutations of binary switches where there should be 5 1 and 4 0. And the array should be of size 9.
I tried the following code. The conditions for the permutations are:
1. The array set should be unique.
2. Not more than 3 1 should be next to each other
const row = [1, 1, 1, 1, 1, 0, 0, 0, 0];
const list = [];
const fullList = [];
// To make sure that no more than 3 `1` are next to each other
const isRowValid = (row) => {
let isValid = true;
for(let i = 0; i+2 < row.length; i++) {
if(row[i] === 1 && row[i+1] === 1 && row[i+2] === 1) {
isValid = false;
break;
}
}
return isValid;
}
const combinations = (row, baseIndex, currentIndex, iterationLevel, list) => {
if(currentIndex > row.length - iterationLevel) {
baseIndex++;
currentIndex = 0;
}
if(baseIndex + iterationLevel > row.length) {
baseIndex = 0;
iterationLevel++;
}
if(iterationLevel === 5) {
return;
}
let rowCopy = [...row]
if(baseIndex > currentIndex ) {
let first = [...row.slice(0, currentIndex)];
let second = [...row.slice(currentIndex)];
let value = second.splice(baseIndex - currentIndex, iterationLevel);
rowCopy = [...first, ...value, ...second]
} else if(baseIndex < currentIndex) {
let first = [...row.slice(0, currentIndex + iterationLevel)];
let second = [...row.slice(currentIndex + iterationLevel)];
let value = first.splice(baseIndex, iterationLevel);
rowCopy = [...first, ...value, ...second];
}
if(isRowValid(rowCopy)) {
list.push(rowCopy);
}
console.log(rowCopy);
combinations(row, baseIndex, currentIndex + 1, iterationLevel, list);
}
combinations(row, 0, 0, 1, list);
list.forEach(l => combinations(l, 0, 0, 1, fullList));
// To remove duplicates
for(let i = 0; i < fullList.length; i++) {
const base = fullList[i]
for(let j = i + 1; j < fullList.length; j++) {
const isSame = fullList[j].every((l, m) => base[m] === l);
if(isSame) {
fullList[j] = [];
}
}
}
let filtered = fullList.filter(l => l.length !== 0);
console.log(filtered.length);
filtered.slice(0, 100).map(i => console.log(i));
console.log(fullList.length);
JS Bin
If I understand correctly, you meant permutations rather than combinations, where in each permutation there shouldn't be more than 3 sequential switches that are "on".
Whenever you have to generate permutations or combinations you can use a recursive backtracking algorithm.
The idea is simple, at every step you follow the possible choices until a base condition is met (e.g. permutation is complete because perm.length === switchCount). When taking a step you reflect that choice on the problem's state and when the recursive call returns you undo these effects.
In order to determine what choices can be made at each step we need to keep track of the problem's state. Here we only need to know how many on/off switches we have left and how many sequential on switches we have so far (seqOn).
const perms = permute(5, 4);
console.log(perms.length);
console.log(perms);
function permute(on, off) {
const switchCount = on + off;
const perm = [], perms = [];
p(on, off, 0);
return perms;
function p(on, off, seqOn) {
if (perm.length === switchCount) {
perms.push([...perm]);
return;
}
if (on && seqOn < 3) {
perm.push(1);
p(on - 1, off, seqOn + 1);
perm.pop();
}
if (off) {
perm.push(0);
p(on, off - 1, 0);
perm.pop();
}
}
}
If we have many permutations to enumerate we can save on memory by using generators too. Here I yield the same perm array which saves the O(n) time copy. As long as you don't need to keep a copy and just enumerate switches it's fine.
for (const perm of permute(5, 4)) {
console.log(perm);
}
function* permute(on, off) {
const switchCount = on + off;
const perm = [];
yield* p(on, off, 0);
function* p(on, off, seqOn) {
if (perm.length === switchCount) {
yield perm;
return;
}
if (on && seqOn < 3) {
perm.push(1);
yield* p(on - 1, off, seqOn + 1);
perm.pop();
}
if (off) {
perm.push(0);
yield* p(on, off - 1, 0);
perm.pop();
}
}
}

Count of values in javascript

I have homework to write a function that will be called with 2 parameters:
a is a list of numbers.
amount represents the count of the numbers in the array.
The function should return the number in the list that occurs amount times.
For example , if a = [5,5,5,3,2,1,1], and amount = 2, the function should return 1, because there are only two ones in the array. If amount = 3, the function should return 5 , if amount = 6, the function will return 0 since there are numbers that occur six time.
try this one
var max=3;
var array=[5,5,5,3,2,1,1];
console.log(verify(array,max))
function verify(array,max) {
var match=0;
array.map(obj => {
if(array.filter(x => x === obj).length == max)
match= obj;
});
return match;
}
Here is a way to get the values by count using reduce.
Since there may be more than one element matching the count, or even 0, an array is returned.
reduce is used to build a map (object) of the unique items to their counts. We the find the map entries where the counts match, and the keys (unique items) for these entries are returned.
const count = (arr, num) => {
const count = arr.reduce((count, x) => {
count[x] = (count[x] || 0) + 1;
return count;
}, {});
return Object.entries(count)
.filter(([k, v]) => v === num)
.map(([k, v]) => +k);
}
console.log(count([5,5,5,3,2,1,1], 1)); // [2, 3]
console.log(count([5,5,5,3,2,1,1], 3)); // [5]
console.log(count([5,5,5,3,2,1,1], 5)); // []
make a array of unique values from real array. Then loop though it and filter() real array to check the count of elements.
const array = [5,5,5,3,2,1,1]
function count(arr,amount){
const unique = [...new Set(arr)];
for(let item of unique){
if(arr.filter(num => num === item).length === amount)
return item;
}
return 0;
}
console.log(count(array,1));
console.log(count(array,2));
console.log(count(array,3));
console.log(count(array,4));
console.log(count(array,5));
You should use below code.
#RaviTeja's code is giving max number of array but you dont want it. You want to number which is same quantity with your "amount" parameter.This code provides this for you
function findingAmount() {
var numberContainer = [ 2, 3, 2,5,2,3 ];
console.log(findingAmountImp(numberContainer,1)); // result 5
console.log(findingAmountImp(numberContainer,2)); // result 3
console.log(findingAmountImp(numberContainer,3)); // result 2
}
function findingAmountImp(numbers,amount) {
var count=1;
for (i=0; i<numbers.length; i++) {
for (j=0; j<numbers.length; j++) {
if(i===j){
j=j+1;
if(j<numbers.length){
if(numbers[i] === numbers[j])
{
count++;
}
}else{
for(k=0;k<i;k++){
if(numbers[i] === numbers[k])
{
count++;
}
}
}
}else{
if(numbers[i] === numbers[j])
{
count++;
}
}
}
if( count === amount){
return numbers[i]
}
count=1;
}
}

Pushing numbers into an array using a for loop. (Find GCF of given number)

I am trying to find the GCF of any number I pass into my function.
When I alert my storage array, all I get is 0.
Why is the only value in my storage array 0? Even though the loop ran 12 times, why are my values not being pushed into the storage array?
let gcf = num => {
let storage = [];
for (let i = 0; i <= num; i++) {
// if it divides evenly into num, it is a factor and we want to push it
// into an array
if (i % num == 0) {
storage.push(i);
} else {
continue;
}
}
// will sort the array from highest to lowest
storage = storage.sort((a, b) => {
return b - a;
})
alert(storage[0]);
// and return storage[0] for the gcf
}
gcf(12);
Your modulo operator was backwards ;)
let gcf = num => {
let storage = [];
for (let i = 0; i <= num; i++) {
// if it divides evenly into num, it is a factor and we want to push it
// into an array
if (num % i == 0) {
storage.push(i);
} else {
continue;
}
}
// will sort the array from highest to lowest
storage = storage.sort((a, b) => {
return a - b;
})
alert(storage[0]);
// and return storage[0] for the gcf
}
gcf(12);

Javascript reduce() until sum of values < variable

I am fetching an array of video durations (in seconds) from a JSON file in Javascript, that, to simplify, would look like this:
array = [30, 30, 30]
I would like to add each value to the previous value until a condition is met (the sum being less than a variable x) and then to get both the new value and the index position in the array of the video to play.
For example if x=62 (condition), I would like the first two values in the array to be added (from my understanding reduce() is appropriate here), and the index = 2 (the second video in the array).
I've got the grasp of reduce():
var count = array.reduce(function(prev, curr, index) {
console.log(prev, curr, index);
return prev + curr;
});
But can't seem to get beyond this point.. Thanks
You could use Array#some, which breaks on a condition.
var array = [30, 30, 30],
x = 62,
index,
sum = 0;
array.some(function (a, i) {
index = i;
if (sum + a > x) {
return true;
}
sum += a;
});
console.log(index, sum);
With a compact result and this args
var array = [30, 30, 30],
x = 62,
result = { index: -1, sum: 0 };
array.some(function (a, i) {
this.index = i;
if (this.sum + a > x) {
return true;
}
this.sum += a;
}, result);
console.log(result);
var a = [2,4,5,7,8];
var index;
var result = [0, 1, 2, 3].reduce(function(a, b,i) {
var sum = a+b;
if(sum<11){
index=i;
return sum;
}
}, 2);
console.log(result,index);
What about using a for loop? This is hack-free:
function sumUntil(array, threshold) {
let i
let result = 0
// we loop til the end of the array
// or right before result > threshold
for(i = 0; i < array.length && result+array[i] < threshold; i++) {
result += array[i]
}
return {
index: i - 1, // -1 because it is incremented at the end of the last loop
result
}
}
console.log(
sumUntil( [30, 30, 30], 62 )
)
// {index: 1, result: 60}
bonus: replace let with var and it works on IE5.5
You could do
var limit = 60;
var array = [30,30,30];
var count = array.reduce(function(prev, curr, index) {
var temp = prev.sum + curr;
if (index != -1) {
if (temp > limit) {
prev.index = index;
} else {
prev.sum = temp;
}
}
return prev;
}, {
sum: 0,
index: -1
});
console.log(count);
What about this : https://jsfiddle.net/rtcgpgk2/1/
var count = 0; //starting index
var arrayToCheck = [20, 30, 40, 20, 50]; //array to check
var condition = 100; //condition to be more than
increment(arrayToCheck, count, condition); //call function
function increment(array, index, conditionalValue) {
var total = 0; //total to add to
for (var i = 0; i < index; i++) { //loop through array up to index
total += array[i]; //add value of array at index to total
}
if (total < conditionalValue) { //if condition is not met
count++; //increment index
increment(arrayToCheck, count, condition); //call function
} else { //otherwise
console.log('Index : ', count) //log what index condition is met
}
}
// define the max outside of the reduce
var max = 20;
var hitIndex;
var count = array.reduce(function(prev, curr, index) {
let r = prev + curr;
// if r is less than max keep adding
if (r < max) {
return r
} else {
// if hitIndex is undefined set it to the current index
hitIndex = hitIndex === undefined ? index : hitIndex;
return prev;
}
});
console.log(count, hitIndex);
This will leave you with the index of the first addition that would exceed the max. You could try index - 1 for the first value that did not exceed it.
You can create a small utility method reduceWhile
// Javascript reduceWhile implementation
function reduceWhile(predicate, reducer, initValue, coll) {
return coll.reduce(function(accumulator, val) {
if (!predicate(accumulator, val)) return accumulator;
return reducer(accumulator, val);
}, initValue)
};
function predicate(accumulator, val) {
return val < 6;
}
function reducer(accumulator, val) {
return accumulator += val;
}
var result = reduceWhile(predicate, reducer, 0, [1, 2, 3, 4, 5, 6, 7])
console.log("result", result);

fastest way to detect if duplicate entry exists in javascript array?

var arr = ['test0','test2','test0'];
Like the above,there are two identical entries with value "test0",how to check it most efficiently?
If you sort the array, the duplicates are next to each other so that they are easy to find:
arr.sort();
var last = arr[0];
for (var i=1; i<arr.length; i++) {
if (arr[i] == last) alert('Duplicate : '+last);
last = arr[i];
}
This will do the job on any array and is probably about as optimized as possible for handling the general case (finding a duplicate in any possible array). For more specific cases (e.g. arrays containing only strings) you could do better than this.
function hasDuplicate(arr) {
var i = arr.length, j, val;
while (i--) {
val = arr[i];
j = i;
while (j--) {
if (arr[j] === val) {
return true;
}
}
}
return false;
}
There are lots of answers here but not all of them "feel" nice... So I'll throw my hat in.
If you are using lodash:
function containsDuplicates(array) {
return _.uniq(array).length !== array.length;
}
If you can use ES6 Sets, it simply becomes:
function containsDuplicates(array) {
return array.length !== new Set(array).size
}
With vanilla javascript:
function containsDuplicates(array) {
return array
.sort()
.some(function (item, i, items) {
return item === items[i + 1]
})
}
However, sometimes you may want to check if the items are duplicated on a certain field.
This is how I'd handle that:
containsDuplicates([{country: 'AU'}, {country: 'UK'}, {country: 'AU'}], 'country')
function containsDuplicates(array, attribute) {
return array
.map(function (item) { return item[attribute] })
.sort()
.some(function (item, i, items) {
return item === items[i + 1]
})
}
Loop stops when found first duplicate:
function has_duplicates(arr) {
var x = {}, len = arr.length;
for (var i = 0; i < len; i++) {
if (x[arr[i]]) {
return true;
}
x[arr[i]] = true;
}
return false;
}
Edit (fix 'toString' issue):
function has_duplicates(arr) {
var x = {}, len = arr.length;
for (var i = 0; i < len; i++) {
if (x[arr[i]] === true) {
return true;
}
x[arr[i]] = true;
}
return false;
}
this will correct for case has_duplicates(['toString']); etc..
var index = myArray.indexOf(strElement);
if (index < 0) {
myArray.push(strElement);
console.log("Added Into Array" + strElement);
} else {
console.log("Already Exists at " + index);
}
You can convert the array to to a Set instance, then convert to an array and check if the length is same before and after the conversion.
const hasDuplicates = (array) => {
const arr = ['test0','test2','test0'];
const uniqueItems = new Set(array);
return array.length !== uniqueItems.size();
};
console.log(`Has duplicates : ${hasDuplicates(['test0','test2','test0'])}`);
console.log(`Has duplicates : ${hasDuplicates(['test0','test2','test3'])}`);
Sorting is O(n log n) and not O(n). Building a hash map is O(n). It costs more memory than an in-place sort but you asked for the "fastest." (I'm positive this can be optimized but it is optimal up to a constant factor.)
function hasDuplicate(arr) {
var hash = {};
var hasDuplicate = false;
arr.forEach(function(val) {
if (hash[val]) {
hasDuplicate = true;
return;
}
hash[val] = true;
});
return hasDuplicate;
}
It depends on the input array size. I've done some performance tests with Node.js performance hooks and found out that for really small arrays (1,000 to 10,000 entries) Set solution might be faster. But if your array is bigger (like 100,000 elements) plain Object (i. e. hash) solution becomes faster. Here's the code so you can try it out for yourself:
const { performance } = require('perf_hooks');
function objectSolution(nums) {
let testObj = {};
for (var i = 0; i < nums.length; i++) {
let aNum = nums[i];
if (testObj[aNum]) {
return true;
} else {
testObj[aNum] = true;
}
}
return false;
}
function setSolution(nums) {
let testSet = new Set(nums);
return testSet.size !== nums.length;
}
function sortSomeSolution(nums) {
return nums
.sort()
.some(function (item, i, items) {
return item === items[i + 1]
})
}
function runTest(testFunction, testArray) {
console.log(' Running test:', testFunction.name);
let start = performance.now();
let result = testFunction(testArray);
let end = performance.now();
console.log(' Duration:', end - start, 'ms');
}
let arr = [];
let setSize = 100000;
for (var i = 0; i < setSize; i++) {
arr.push(i);
}
console.log('Set size:', setSize);
runTest(objectSolution, arr);
runTest(setSolution, arr);
runTest(sortSomeSolution, arr);
On my Lenovo IdeaPad with i3-8130U Node.js v. 16.6.2 gives me following results for the array of 1,000:
results for the array of 100,000:
Assuming all you want is to detect how many duplicates of 'test0' are in the array. I guess an easy way to do that is to use the join method to transform the array in a string, and then use the match method.
var arr= ['test0','test2','test0'];
var str = arr.join();
console.log(str) //"test0,test2,test0"
var duplicates = str.match(/test0/g);
var duplicateNumber = duplicates.length;
console.log(duplicateNumber); //2

Categories

Resources