Functions that takes array as argument and generate random numbers - javascript

First of all, any of built-in methods cannot be used. ex. pop(), shift(). What I can use is merely loops, array and so on.
I would like to make a function which takes an array as an argument and generate random strings of numbers, which does not contain these numbers given in the array.
For instance, func([6, 2]) //=> "20353" (2 and 6 would not be there).
The array length could change ([6, 2, 9], [7, 2, 1, 9]). So the function has to have an ability to accommodate any length of an array.
In order to tackle this practice question, I have used for and while loops. However, I ran into a problem that, when the second index is checked (whether numbers randomly generated contain 2 or not, in the example), if it contains, I regenerate the random number and it could produce the first index number (in this case, 6) which I do not want.
Please see the code I posted below and help me solve this. On top of that, if there is another way to get the same result which is a better way, please let me know too.
let str = "";
let arr = [];
let tem
const func = arg2 => {
for (let i = 0; i < 5; i++) {
arr[i] = Math.floor(Math.random() * 10);
}
for (let i = 0; i < arr.length; i++) {
for (let v = 0; v < arg2.length; v++) {
if (arg2[v] == arr[i]) {
do {
tem = Math.floor(Math.random() * 10);
} while (tem == arr[i])
arr[i] = tem;
}
}
}
for (let i = 0; i < arr.length; i++) str += arr[i]
return str
}
console.log(func([6, 2]))
// the output will not contain 2, which is the last index element
// however, when the second index number is removed, the output might replace it with 6, which is the first index element
Expected output:
func([6, 3, 8]) //=> "45102"
func([4, 9]) //=> "55108"

First, you already use two native methods (floor and random), but I'll assume you're OK with that.
Secondly, in your question the term digit would have been more appropriate in some instances than number. There is a difference...
To avoid that you still select a digit that is not allowed, you could first build an array with digits that are still allowed, and then randomly pick values from that array. That way you will not ever pick a wrong one.
Here is how that would look:
const func = arg2 => {
const digits = [0,1,2,3,4,5,6,7,8,9];
// Mark digits that are not allowed with -1
for (let i=0; i<arg2.length; i++) {
digits[arg2[i]] = -1;
}
// Collect digits that are still allowed
const allowed = [];
for (let i=0; i<digits.length; i++) {
if (digits[i] > -1) allowed[allowed.length] = digits[i];
}
// Pick random digits from the allowed digits
let str = "";
for(let i=0; i<5; i++) {
str += allowed[Math.floor(Math.random() * allowed.length)];
}
return str;
}
console.log(func([6, 2]));
Just for fun, if you lift the restrictions on what language aspects cannot be used, you can do this as follows:
const func = arg2 => {
const digits = new Set(Array(10).keys());
for (let digit of arg2) digits.delete(digit);
const allowed = [...digits];
return Array.from({length:5}, () =>
allowed[Math.floor(Math.random() * allowed.length)]
).join``;
}
console.log(func([6, 2]));

I suspect you're overthinking this. The basic algorithm is:
In a loop:
If output has 5 digits, return it.
Otherwise
Pick a random digit n from 0 to 9.
If n is not in the list of excluded numbers, it to output.
This maps pretty directly to the following function:
function fn(exclude, length = 5) {
let output = '';
while (output.length < length) {
const n = Math.floor(Math.random() * 10)
if (!exclude.includes(n)) {
output += n;
}
}
return output;
}
console.log(fn([6,3,8]));
There are, of course, other ways to achieve this, such as initializing an array with five elements and then joining the elements:
function fn(exclude, length = 5) {
return Array.from({ length }, () => {
let n;
while (n = Math.floor(Math.random() * 10), exclude.includes(n)) {}
return n;
}).join('');
}
console.log(fn([6,3,8]));

You need to loop through the entire arg2 array each time you pick a random digit. You can't replace the value in the arg2 loop, because then you won't check against earlier elements.
You don't need the arr array, you can append to str in the loop.
const func = arg2 => {
let str = "";
let arr = [];
for (let i = 0; i < 5; i++) {
let random;
while (true) {
let ok = true;
random = Math.floor(Math.random() * 10);
for (let j = 0; j < arg2.length; j++) {
if (random == arg2[j]) {
ok = false;
break;
}
}
if (ok) {
break;
}
}
str += random
}
return str
}
console.log(func([6, 2]))

Besides the fact (what others stated as well) that you use native array-methods yourself, I would probably go for it with something like this (using only what you used so far):
const func = without => {
let result = '';
while (result.length < 5) {
let rand = Math.floor(Math.random() * 10);
let add = true;
for (i=0; i<without.length; i++) {
if (rand === without[i]) {
add = false;
}
}
if (add) {
result += rand;
}
}
return result;
}
console.log(func([6, 2]))
a more concise version using native array methods could look like this:
const func = without => {
let result = '';
while (result.length < 5) {
let rand = Math.floor(Math.random() * 10);
if (!without.includes(rand)) {
result += rand;
}
}
return result;
}
console.log(func([6, 2]))

Related

How to tweak this function to make it passable?

I'm doing an interview prep challenge on FCC: https://www.freecodecamp.org/learn/coding-interview-prep/algorithms/no-repeats-please. The function takes a string of letters as an argument and creates all possible permutations of it, so abc becomes
abc, acb, bca, bac, cab, cba . It then returns the amount of permutations that don't have repeated consecutive letters in it, so aab returns 2. I wrote a function that does the job but does it so horribly that it still fails two of the conditions of the test, even though it still does return the correct results…after 46 seconds. But that’s for 7 letters, for a smaller number of letters it works ok. Some code editors will crash if you use 7 letters though, so use a sturdy one like Programiz if you want to run this code. My question is, can this code be modified to pass the test, while still preserving the logic?
function permAlone(arg) {
let length = arg.length
let arr = []
function uniqueIndices() { // generate a set of non-repeating integers to represent indices
let indices = new Array(length)
for (let i = 0; i < indices.length; i++) {
let r = Math.floor(Math.random() * length)
if (indices.indexOf(r) === -1) {
indices[i] = r
} else {
i--
}
}
return indices
}
function factorial(n) {
let product = 1;
for (let i = 2; i <= n; i++) {
product *= i;
}
return product;
}
let length2 = factorial(arg.length) // factorialize the length of arg to set the length of next loop which will be filled with sets of non-repeating integers
for (let i = 0; i < length2; i++) {
let val = uniqueIndices(arg)
if (arr.map(a => a.join('')).indexOf(val.join('')) === -1) { // make sure the sets of integers are all unique
arr[i] = val
} else {
i--
}
}
for (let indices of arr) { // now that we have the unique sets of non-repeating indices, convert each integer in the set to a letter in arg with the corresponding index
for (let i = 0; i < indices.length; i++) {
indices[i] = arg[indices[i]]
}
}
function final(a) { // final function to record the number of sets that have repeated consecutive letters
let ct = 0;
for (let x of a) {
for (let i = 0; i < x.length; i++) {
if (x[i] === x[i + 1]) {
ct++
break;
}
}
}
return ct
}
// to find the number of sets without repeated consecutive letters, substract the number of sets with repeated consecutive letters from arr.length
return arr.length - final(arr)
}
console.log(permAlone(['a', 'b', 'c', 'd', 'e']))

Combine two small functions into one

So I am trying to "write a function Single() that takes a number and returns the number of times you must multiply the digits in num so as to reach a single digit. e.g. Single(456)//4*5*6=120, 1*2*0=0//it takes two loops to to reach the single digit so the return would be 2.
My problem is that now I have to put in an array of individual digits instead of a number. So I probably need to combine the two functions.
function numberToArray(num) {
var tmpString = num.toString();
var tempArray = [];
for (var i = 0; i < tmpString.length; i++) {
tempArray.push(tmpString[i]);
}
return tempArray;
}
function reachSingle(tempArray) {
var count = 0;
var k = 1;
for (var i = 0; i < tempArray.length; i++) {
k *= tempArray[i];
}
count++;
if (k <= 10) return count;
else {
var newArray = numberToArray(k);
return count + reachSingle(newArray);
}
}
document.write(reachSingle([2, 9, 3, 7, 6]));
You could take a recursive approach with an exit condition for numbers smaller than 10 and return in this case zero. Otherwise return one plus the result of the call of the product of the digits.
function reachSingle(n) {
if (n < 10) return 0;
return 1 + reachSingle(Array.from(n.toString()).reduce((a, b) => a * b));
}
console.log(reachSingle(29376)); // 4

How to use array.push inside a function

I'm trying to return the array an array of numbers that conform to the two if statements. The prompt came from leet code, "Self Dividing Numbers", and asks to take in two arguments, a lower and upper bound and check if whether or not each number in that range is divisible by the digits of each individual number.
When I console.log(num) (the commented out portion, I get a correct list of numbers, but not in an array format. To fix this I thought to add a variable, result and return result after pushing an array to result inside the for loop. However when I do this, i only get the first correct term in an array, but not the full array.
How can this be fixed? I've tried moving the return statement in various locations, but that did not fix the issue.
The function should return [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15, 22];
function selfDividingNumbers(left, right) {
for (let j = left; j <= right; j++) {
let num = j;
let result = []
let strNum = num.toString();
let dividingDigit = 0;
for (let i = 0; i < strNum.length; i++) {
if (num % parseInt(strNum[i]) == 0) {
dividingDigit++;
}
if (dividingDigit == strNum.length) {
result.push(num)
//console.log(num)
}
}
return result
}
};
console.log(selfDividingNumbers(1, 22));
From your expected output, define result at the very top of the function, and then return only after completely iterating through both loops:
function selfDividingNumbers(left, right) {
let result = []
for (let j = left; j <= right; j++) {
let num = j;
let strNum = num.toString();
let dividingDigit = 0;
for (let i = 0; i < strNum.length; i++) {
if (num % parseInt(strNum[i]) == 0) {
dividingDigit++;
}
if (dividingDigit == strNum.length) {
result.push(num)
//console.log(num)
}
}
}
return result
};
console.log(selfDividingNumbers(1, 22));
To be more concise, you might use .filter check whether .every digit divides evenly:
function selfDividingNumbers(left, right) {
return Array.from(
{ length: right - left },
(_, i) => i + left
)
.filter((num) => {
const digits = String(num).split('');
if (digits.includes(0)) {
return false;
}
return digits.every(digit => num % digit === 0);
});
}
console.log(selfDividingNumbers(1, 22));
When you declare let result = [] inside your for loop you are telling your code to recreate this array every time your loop iterates, thus, removing all previous results pushed into it. Instead, you need to move this outside your for loop to stop this from happening.
Lastly, you need to return only after you're outer for loop is complete, as returning inside your for loop will stop the function from running (and thus stop the loop).
See working example below:
function selfDividingNumbers(left, right) {
let result = [];
for (let j = left; j <= right; j++) {
let num = j;
let strNum = num.toString();
let dividingDigit = 0;
for (let i = 0; i < strNum.length; i++) {
if (num % parseInt(strNum[i]) == 0) {
dividingDigit++;
}
if (dividingDigit == strNum.length) {
result.push(num)
}
}
}
return result
};
console.log(selfDividingNumbers(1, 22));

How to code all for all cases of Two Sum javascript problem

I have been working on the two sum problem for the past few hours and can't seem to account for the case where there are only two numbers and their sum is the same as the first number doubled.
The result should be [0,1], but i'm getting [0,0].
let nums = [3,3];
let targetNum = 6;
function twoSum(nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let b = i+1; b < nums.length; b++) {
if ((nums[i] + nums[b]) == target) {
return [nums.indexOf(nums[i]), nums.indexOf(nums[b])];
}
}
}
}
console.log(twoSum(nums, targetNum))
Two Sum
My approach uses a javascript object and completes the algorithm in O(n) time complexity.
const twoSum = (nums, target) => {
let hash = {}
for(i=0;i<nums.length;i++) {
if (hash[nums[i]]!==undefined) {
return [hash[nums[i]], i];
}
hash[target-nums[i]] = i;
}
};
console.log(twoSum([2,7,11,15], 9)); // example
This is not the way to solve the problem. Step through the array and save the complement of the target wrt the number in the array. This will also solve your corner case.
You should consider, indexOf(i) -> start from the first element, returns the index when match found! That is why in your code, nums.indexOf(nums[i]) and nums.indexOf(nums[b]) which is basically 3 in all two cases, it will return 0, cause 3 is the first element in array.
instead of doing this, return the index itself.
let nums = [3,3];
let targetNum = 6;
function twoSum(nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let b = i+1; b < nums.length; b++) {
if ((nums[i] + nums[b]) == target) {
return i + "" +b;
}
}
}
}
console.log(twoSum(nums, targetNum))

Arrays - Find missing numbers in a Sequence

I'm trying to find an easy way to loop (iterate) over an array to find all the missing numbers in a sequence, the array will look a bit like the one below.
var numArray = [0189459, 0189460, 0189461, 0189463, 0189465];
For the array above I would need 0189462 and 0189464 logged out.
UPDATE : this is the exact solution I used from Soufiane's answer.
var numArray = [0189459, 0189460, 0189461, 0189463, 0189465];
var mia= [];
for(var i = 1; i < numArray.length; i++)
{
if(numArray[i] - numArray[i-1] != 1)
{
var x = numArray[i] - numArray[i-1];
var j = 1;
while (j<x)
{
mia.push(numArray[i-1]+j);
j++;
}
}
}
alert(mia) // returns [0189462, 0189464]
UPDATE
Here's a neater version using .reduce
var numArray = [0189459, 0189460, 0189461, 0189463, 0189466];
var mia = numArray.reduce(function(acc, cur, ind, arr) {
var diff = cur - arr[ind-1];
if (diff > 1) {
var i = 1;
while (i < diff) {
acc.push(arr[ind-1]+i);
i++;
}
}
return acc;
}, []);
console.log(mia);
If you know that the numbers are sorted and increasing:
for(var i = 1; i < numArray.length; i++) {
if(numArray[i] - numArray[i-1] != 1) {
//Not consecutive sequence, here you can break or do whatever you want
}
}
ES6-Style
var arr = [0189459, 0189460, 0189461, 0189463, 0189465];
var [min,max] = [Math.min(...arr), Math.max(...arr)];
var out = Array.from(Array(max-min),(v,i)=>i+min).filter(i=>!arr.includes(i));
Result: [189462, 189464]
Watch your leading zeroes, they will be dropped when the array is interpreted-
var A= [0189459, 0189460, 0189461, 0189463, 0189465]
(A returns [189459,189460,189461,189463,189465])
function absent(arr){
var mia= [], min= Math.min.apply('',arr), max= Math.max.apply('',arr);
while(min<max){
if(arr.indexOf(++min)== -1) mia.push(min);
}
return mia;
}
var A= [0189459, 0189460, 0189461, 0189463, 0189465];
alert(absent(A))
/* returned value: (Array)
189462,189464
*/
To find a missing number in a sequence, First of all, We need to sort an array. Then we can identify what number is missing. I am providing here full code with some test scenarios. this code will identify only missing positive number, if you pass negative values even then it gives positive number.
function findMissingNumber(inputAr) {
// Sort array
sortArray(inputAr);
// finding missing number here
var result = 0;
if (inputAr[0] > 1 || inputAr[inputAr.length - 1] < 1) {
result = 1;
} else {
for (var i = 0; i < inputAr.length; i++) {
if ((inputAr[i + 1] - inputAr[i]) > 1) {
result = inputAr[i] + 1;
}
}
}
if (!result) {
result = inputAr[inputAr.length - 1] + 1;
}
return result;
}
function sortArray(inputAr) {
var temp;
for (var i = 0; i < inputAr.length; i++) {
for (var j = i + 1; j < inputAr.length; j++) {
if (inputAr[j] < inputAr[i]) {
temp = inputAr[j];
inputAr[j] = inputAr[i];
inputAr[i] = temp;
}
}
}
}
console.log(findMissingNumber([1, 3, 6, 4, 1, 2]));
console.log(findMissingNumber([1, 2, 3]));
console.log(findMissingNumber([85]));
console.log(findMissingNumber([86, 85]));
console.log(findMissingNumber([0, 1000]));
This can now be done easily as a one-liner with the find method:
const arr = [1,2,3,5,6,7,8,9];
return arr.find((x,i) => arr[i+1]-x > 1) + 1
//4
const findMissing = (arr) => {
const min = Math.min(...arr);
const max = Math.max(...arr);
// add missing numbers in the array
let newArr = Array.from(Array(max-min), (v, i) => {
return i + min
});
// compare the full array with the old missing array
let filter = newArr.filter(i => {
return !arr.includes(i)
})
return filter;
};
const findMissing = (numarr) => {
for(let i = 1; i <= numarr.length; i++) {
if(i - numarr[i-1] !== 0) {
console.log('found it', i)
break;
} else if(i === numarr.length) console.log('found it', numarr.length + 1)
}
};
console.log(findMissing([1,2,3,4,5,6,7,8,9,10,11,12,13,14]))
It would be fairly straightforward to sort the array:
numArray.sort();
Then, depending upon what was easiest for you:
You could just traverse the array, catching sequential patterns and checking them as you go.
You could split the array into multiple arrays of sequential numbers and then check each of those separate arrays.
You could reduce the sorted array to an array of pairs where each pair is a start and end sequence and then compare those sequence start/ends to your other data.
function missingNum(nums){
const numberArray = nums.sort((num1, num2)=>{
return num1 - num2;
});
for (let i=0; i < numberArray.length; i++){
if(i !== numberArray[i]){
return i;
}
}
}
console.log(missingNum([0,3,5,8,4,6,1,9,7]))
Please check below code.....
function solution(A) {
var max = Math.max.apply(Math, A);
if(A.indexOf(1)<0) return 1;
var t = (max*(max+1)/2) - A.reduce(function(a,b){return a+b});
return t>0?t:max+1;
}
Try as shown below
// Find the missing number
let numArray = [0189459, 0189460, 0189461, 0189463, 0189468];
let numLen = numArray.length;
let actLen = Number(numArray[numLen-1])-Number(numArray[0]);
let allNumber = [];
for(let i=0; i<=actLen; i++){
allNumber.push(Number(numArray[0])+i);
}
[...allNumber].forEach(ele=>{
if(!numArray.includes(ele)){
console.log('Missing Number -> '+ele);
}
})
I use a recursive function for this.
function findMissing(arr, start, stop) {
var current = start,
next = stop,
collector = new Array();
function parseMissing(a, key) {
if(key+1 == a.length) return;
current = a[key];
next = a[key + 1];
if(next - current !== 1) {
collector.push(current + 1);
// insert current+1 at key+1
a = a.slice( 0, key+1 ).concat( current+1 ).concat( a.slice( key +1 ) );
return parseMissing(a, key+1);
}
return parseMissing(a, key+1);
}
parseMissing(arr, 0);
return collector;
}
Not the best idea if you are looking through a huge set of numbers. FAIR WARNING: recursive functions are resource intensive (pointers and stuff) and this might give you unexpected results if you are working with huge numbers. You can see the jsfiddle. This also assumes you have the array sorted.
Basically, you pass the "findMissing()" function the array you want to use, the starting number and stopping number and let it go from there.
So:
var missingArr = findMissing(sequenceArr, 1, 10);
let missing = [];
let numArray = [3,5,1,8,9,36];
const sortedNumArray = numArray.sort((a, b) => a - b);
sortedNumArray.reduce((acc, current) => {
let next = acc + 1;
if (next !== current) {
for(next; next < current; next++) {
missing.push(next);
}
}
return current;
});
Assuming that there are no duplicates
let numberArray = [];
for (let i = 1; i <= 100; i++) {
numberArray.push(i);
}
let deletedArray = numberArray.splice(30, 1);
let sortedArray = numberArray.sort((a, b) => a - b);
let array = sortedArray;
function findMissingNumber(arr, sizeOfArray) {
total = (sizeOfArray * (sizeOfArray + 1)) / 2;
console.log(total);
for (i = 0; i < arr.length; i++) {
total -= arr[i];
}
return total;
}
console.log(findMissingNumber(array, 100));
Here is the most efficient and simple way to find the missing numbers in the array. There is only one loop and complexity is O(n).
/**
*
* #param {*} item Takes only the sorted array
*/
function getAllMissingNumbers(item) {
let first = 0;
let second = 1;
let currentValue = item[0];
const container = [];
while (first < second && item[second]) {
if ((item[first] + 1) !== item[second]) { // Not in sequence so adds the missing numbers in an array
if ((currentValue + 1) === item[second]) { // Moves the first & second pointer
first = second;
second++;
currentValue = item[first];
} else { // Adds the missing number between two number
container.push(++currentValue);
}
} else { // Numbers are in sequence so just moves the first & second pointer
first = second;
second++;
currentValue = item[first];
}
}
return container;
}
console.log(getAllMissingNumbers([0189459, 0189460, 0189461, 0189463, 0189465].sort( (a, b) => a - b )));
console.log(getAllMissingNumbers([-5,2,3,9]));
Adding one more similar method
Find the min and max of the numbers in the array
Loop with the max and min numbers to get the full list
compare the full list of numbers with the input array to get the difference
const array = [0189459, 0189460, 0189461, 0189463, 0189465]
const max = Math.max(...array)
const min = Math.min(...array)
let wholeNumber = []
for(var i = min ;i<=max ;i++ ){
wholeNumber.push(i)
}
const missing = wholeNumber.filter((v)=>!array.includes(v))
console.log('wholeNumber',wholeNumber)
console.log('missingNumber',missing)
Here's a variant of #Mark Walters's function which adds the ability to specify a lower boundary for your sequence, for example if you know that your sequence should always begin at 0189455, or some other number like 1.
It should also be possible to adjust this code to check for an upper boundary, but at the moment it can only look for lower boundaries.
//Our first example array.
var numArray = [0189459, 0189460, 0189461, 0189463, 0189465];
//For this array the lowerBoundary will be 0189455
var numArrayLowerBoundary = 0189455;
//Our second example array.
var simpleArray = [3, 5, 6, 7, 8, 10, 11, 13];
//For this Array the lower boundary will be 1
var simpleArrayLowerBoundary = 1;
//Build a html string so we can show our results nicely in a div
var html = "numArray = [0189459, 0189460, 0189461, 0189463, 0189465]<br>"
html += "Its lowerBoundary is \"0189455\"<br>"
html += "The following numbers are missing from the numArray:<br>"
html += findMissingNumbers(numArray, numArrayLowerBoundary);
html += "<br><br>"
html += "simpleArray = [3, 5, 6, 7, 8, 10, 11, 13]<br>"
html += "Its lowerBoundary is \"1\".<br>"
html += "The following numbers are missing from the simpleArray:<br>"
html += findMissingNumbers(simpleArray, simpleArrayLowerBoundary);
//Display the results in a div
document.getElementById("log").innerHTML=html;
//This is the function used to find missing numbers!
//Copy/paste this if you just want the function and don't need the demo code.
function findMissingNumbers(arrSequence, lowerBoundary) {
var mia = [];
for (var i = 0; i < arrSequence.length; i++) {
if (i === 0) {
//If the first thing in the array isn't exactly
//equal to the lowerBoundary...
if (arrSequence[i] !== lowerBoundary) {
//Count up from lowerBoundary, incrementing 1
//each time, until we reach the
//value one less than the first thing in the array.
var x = arrSequence[i];
var j = lowerBoundary;
while (j < x) {
mia.push(j); //Add each "missing" number to the array
j++;
}
} //end if
} else {
//If the difference between two array indexes is not
//exactly 1 there are one or more numbers missing from this sequence.
if (arrSequence[i] - arrSequence[i - 1] !== 1) {
//List the missing numbers by adding 1 to the value
//of the previous array index x times.
//x is the size of the "gap" i.e. the number of missing numbers
//in this sequence.
var x = arrSequence[i] - arrSequence[i - 1];
var j = 1;
while (j < x) {
mia.push(arrSequence[i - 1] + j); //Add each "missing" num to the array
j++;
}
} //end if
} //end else
} //end for
//Returns any missing numbers, assuming that lowerBoundary is the
//intended first number in the sequence.
return mia;
}
<div id="log"></div> <!-- Just used to display the demo code -->

Categories

Resources