Why is this infinite loop? - javascript

I am trying to place three strings into an array size of 9 that holds them three string placed at random indexes in the array but how I am trying to do it is resulting in an infinite loop
const ticketArray = [];
const victoryMultipliers = ["x10", "x20", "x30", "x40", "x50", "x60"];
const threeOfThem = [];
let arr = []
let randStr = "";
for (let i = 0; i < 3; i++) {
threeOfThem[i] = victoryMultipliers[Math.floor(Math.random() * victoryMultipliers.length)]
randStr = threeOfThem[i]
//console.log(randStr)
arr = threeOfThem.filter(val => val === randStr)
if (arr.length >= 2) {
threeOfThem.pop();
i--;
}
}
const threeTicketArray = threeOfThem;
/// So above we have an array of example ["x20", "x50", "x30"]
// so below is where we have some problem
let randInt;
let tempStr = "";
for (let i = 0; i < 10; i++) { // i want to make an array.length of 9
randInt = Math.floor( Math.random() * 3 );
tempStr = threeTicketArray[randInt]; // to find the "x30" or whichever i stored
ticketArray.push(tempStr); // push it into the ticketArray
let len = ticketArray.filter(val => val === tempStr) // we filter to bring out the once for this loops iteration
if ( len.length > 3 ) { // if I have 4 of example "x30"
ticketArray.pop(); // I remove it as it was the last "x30" string added to the array
i--; // I subtract the iteration by 1 so I can restart the this iteration of the loop
}
}
// the end of the loop
console.log(ticketArray);
So at random I want ticketArray to be of size 9 the ticket strings to be placed at a random index and each string appears 3 times. However, I am getting an infinite loop I can't understand why!

See the solution below, and tell me what you think
const ticketArray = [];
const victoryMultipliers = ["x10", "x20", "x30", "x40", "x50", "x60"];
const threeOfThem = [];
let arr = []
let randStr = "";
for (let i = 0; i < 3; i++) {
threeOfThem[i] = victoryMultipliers[Math.floor(Math.random() * victoryMultipliers.length)]
randStr = threeOfThem[i]
//console.log(randStr)
arr = threeOfThem.filter(val => val === randStr)
if (arr.length >= 2) {
threeOfThem.pop();
i--;
}
}
const threeTicketArray = threeOfThem;
/// So above we have an array of example ["x20", "x50", "x30"]
// so below is where we have some problem
let randInt;
let tempStr = "";
for (let i = 0; i < 10; i++) { // i want to make an array.length of 9
randInt = Math.floor( Math.random() * 3 );
tempStr = threeTicketArray[randInt]; // to find the "x30" or whichever i stored
ticketArray.push(tempStr); // push it into the ticketArray
let len = ticketArray.filter(val => val === tempStr) // we filter to bring out the once for this loops iteration
if ( len.length > 3 ) { // if I have 4 of example "x30"
ticketArray.pop();
// this should solve the infinit loop issue.
// as it seems that randInt is generating duplicated.
if (ticketArray.length <9)
i--
}
}
// the end of the loop
console.log(ticketArray);

You can do:
const victoryMultipliers = ["x10", "x20", "x30", "x40", "x50", "x60"]
const vmCopy = [...victoryMultipliers]
const randomVM = arr => arr
.splice(Math.floor(Math.random() * arr.length), 1)
.pop()
const ticketArray = [...Array(3)]
.map(() => randomVM(vmCopy))
.reduce((a, c, i, arr) => a.concat(arr), [])
.map(v => ({ v, s: Math.random() }))
.sort((a, b) => a.s - b.s)
.map(({ v }) => v)
console.log(ticketArray)

Related

Calculate duplicated letters next to each other

I need to calculate pairs of same letters that stay each other in twos, I got this code
const calculateLetters = (text: string) => {
const arrayStr = [...text];
let count = 0;
for (let i = 0; i < arrayStr.length; i++) {
if (arrayStr[i] === arrayStr[i + 1]) {
count += 1;
}
}
return count;
};
console.log(calculateLetters('ABBAAA'));
But now it returns 3, what I need to do is make count equal 2, because I need to calculate pairs of same letters.
In your if statement, if you've found a pair, then iterate till the point your i+1th element is not same as ith element, and then count again.
You can accomplish this with RegEx The below pattern will count matches of the same character pairs.
const countPairs = (text) => {
//Grab the matches length if any exist, otherwise return 0
return (text.match(/(.)\1/g))?.length ?? 0
}
console.log(countPairs("abc")) //Result is 0
console.log(countPairs("ABBAAA")) //Result is 2
console.log(countPairs("aabBccDD111")) //Result is 4
With your code, you just need to move past the match when you find one
const calculateLetters = (text) => {
const arrayStr = [...text];
let count = 0;
for (let i = 0; i < arrayStr.length; i++) {
if (arrayStr[i] === arrayStr[i + 1]) {
count += 1;
//move past the match
i++;
}
}
return count;
};
console.log(calculateLetters('ABBAAA'));
const calculateLetters = (text: string) => {
const arrayStr = [...text];
let count = 0;
for (let i = 0; i < arrayStr.length; i++) {
let j = i;
while(i + 1 < arrayStr.length && arrayStr[i] === arrayStr[i + 1]) {
i+= 1;
}
if(i != j){
count += 1;
}
}
return count;
};
console.log(calculateLetters('ABBAAA'));
Define a zip function that can be used to create a list of pairs of adjacent letters in the text. Then count the pairs that match.
Since you want unique adjacent letters, pass the pairs through a Set before counting.
const zip = (a, b) => a.map((k, i) => [k, b[i]])
const calculateLetters = (text) => {
const chars = [...text]
const adjacentLetters = zip(chars, chars.slice(1))
const uniqueAdjacentLetters = [
...new Set(adjacentLetters.map(([a,b]) => `${a}:${b}`))
].map(x => x.split(':'))
const count = uniqueAdjacentLetters.reduce(
(total, [a,b]) => total + ((a === b) ? 1 : 0),
0,
)
return count
}
console.log(calculateLetters('ABBAAA'))

How to split array into equal parts based on values?

Input Arr=[1,2,3,4,5,6,7,8,9,10]
Expected output:-
Arr1 = [1,2,3,4,5,6,7] = 28
Arr2 = [8,9,10] = 27
The sum of arrays should be almost the same..
It can also be 3 or more parts
How to achieve this via custom function?
let Arr = [1,2,3,4,5,6,7,8,9,10]
const numberOfParts = 2
function SplitArr(Array, Parts){
/* ... */
}
let result = SplitArr(Arr,numberOfParts)
/* result should be [[1,2,3,4,5,6,7],[8,9,10]] */
/* output can be in any format as long as it can get the parts */
I think you can't do that directly by JS functions.
You have to create a custom function to achieve this.
I have considered dividing the array into 2 equal parts.
You can't always split the array equally. Here in this array, you can't partition array into more than 2 subparts, otherwise it will give more than 3 parts as some of the elements are present there having sum more than the partitioned Sum.
Note: I treated the array to be sorted, otherwise it depends on the usecase.
Note: I have updated the old implementation based on the updated question requirement
let arr=[1,2,3,4,5,6,7,8,9,10]
function splitArrayEqually(arr, parts=2){
//get the total sum of the array
let sum = arr.reduce((currentSum, value) => currentSum+value ,0);
//get the half sum of the array
let partitionedSum = Math.ceil(sum/parts);
let start=0, end=0, currentSum=0;
let splittedArray=[];
//get the index till which the sum is less then equal partitioned sum
while(end < arr.length){
if(currentSum+arr[end] > partitionedSum){
splittedArray.push(arr.slice(start,end));
start = end; //start new window from current index
currentSum = 0; //make sum =0
}
//add current end index to sum
currentSum += arr[end];
end++;
}
splittedArray.push(arr.slice(start));
return splittedArray;
}
splitted = splitArrayEqually(arr,3);
console.log(splitted)
let Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const numberOfParts = 3
function sumOfArray(arr) {
if (arr) {
if (arr.length > 0) {
let sum = 0
for (let i = 0; i < arr.length; i++) sum += arr[i]
return sum
} else {
return 0
}
} else {
return 0
}
}
function SplitArr(Array, Parts) {
let lastIndex = 0
let result = []
function getReamingSum(arr) {
let psum = sumOfArray(Array.slice(lastIndex)) / Parts
console.log('psum ' + psum)
return psum + Parts
}
let psum = getReamingSum(Array)
for (let j = 0; j < Parts; j++) {
let total = 0
for (let i = 0; i < Array.length; i++) {
if (i >= lastIndex) {
total += Array[i]
if (total < psum || j === Parts - 1) {
if (result[j]?.length > 0) {
result[j].push(Array[i])
} else {
let arr = []
arr.push(Array[i])
result[j] = arr
}
lastIndex = i + 1
}
}
}
}
return result
}
let result = SplitArr(Arr, numberOfParts)
console.log(result)
Assuming the array isn't sorted,using a 2D array, with each sub array with sum almost equal to (sum of array / n).
let arr = [9,2,10,4,5,6,7,8,1,3]
arr.sort(function(a, b) { return a - b; });
const sum = arr.reduce((a, b) => a + b, 0);
const n = 2;
const result = [];
let s = 0;
let j = 0;
result[j] = [];
for(let i=0; i<arr.length; i++){
if(s <= Math.floor(sum/n)){
result[j].push(arr[i]);
s +=arr[i];
}
else{
s = 0;
j = j + 1;
result[j] = [];
result[j].push(arr[i]);
}
}
console.log(result)
O/P:
[ [1, 2, 3, 4,5, 6, 7], [ 8, 9, 10 ] ]
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const splitArray = (arr,parts) => {
const totalSum = arr.reduce((acc, item) => {
acc += item;
return acc;
}, 0)
const splitSum = Math.floor(totalSum / parts);
const arrObj = arr.reduce((acc, item,index) => {
acc.sum = acc.sum || 0;
acc.split = acc.split || {};
const pointer = Math.floor(acc.sum / splitSum);
//console.log(item,acc.sum, splitSum, pointer);
acc.split[pointer] = acc.split[pointer] || [];
acc.split[pointer].push(item);
acc.splitSum = splitSum;
acc.sum += item;
return acc;
}, {})
return arrObj;
}
console.log(splitArray(arr,2).split)
You're better off making a custom function:
let currentTotal = 0
let tempList = []
Arr.forEach(val => {
if (val >= 27) {
// push tempList to a new array
tempList = [];
currentTotal = val;
} else {
tempList.push(val);
currentTotal += val;
}
})

Let N and M be natural numbers. Find the sum of the last M digits of the number N

I dont have any idea how to sovle it :
const SumOfNum = (N,M)=>{
var res = N.toString().split('');
var arr = res.[length-1]
return N*arr
}
A simple example using reduce:
const sumLastDigits = (n, m) => {
const str = n.toString()
const last = str.slice(str.length - m)
return Array.from(last).reduce((prev, curr) => prev + Number(curr), 0)
}
console.log(
sumLastDigits(1234, 2)
)
This is a commented example:
function myFunction(n, m) {
// CONVERT n TO STRING AND SPLIT INTO AN ARRAY OF CHARACTERS.
const arr = [...n.toString()];
const length = arr.length;
const start = length - 1;
const end = start - m;
let count = 0;
// LOOP THROUGH THE ARRAY FROM THE END.
for (let i = start; i > end; i--) {
// CONVERT CHARACTER TO INTEGER AND SUM.
count += parseInt(arr[i]);
}
return count;
}
console.log(myFunction(54321, 1)); // 1
console.log(myFunction(54321, 2)); // 3
console.log(myFunction(54321, 3)); // 6
console.log(myFunction(54321, 4)); // 10
console.log(myFunction(54321, 5)); // 15

Not able to get value after Do...While loop

Question: Create a function that takes a positive integer and returns the next bigger number that can be formed by rearranging its digits. For example:
12 ==> 21
513 ==> 531
2017 ==> 2071
//nextBigger(num: 12) // returns 21
//nextBigger(num: 513) // returns 531
//nextBigger(num: 2017) // returns 2071
I am trying to compare two Array and get correct array as answer. In do...while loop I am comparing the two array by increment second array by one.
function nextBigger(n){
let nStrg = n.toString();
let nArr = nStrg.split('');
function compareArr(Ar1,Ar2){
if(Ar2.length>Ar1.length){
return false;
}
for(let i=0; i<Ar1.length; i++){
let num = Ar1[i];
for(let j=0; j<Ar2.length; j++){
if(Ar2.lastIndexOf(num) !== -1){
Ar2.splice(Ar2.lastIndexOf(num), 1);
break;
}
else{
return false;
break;
}
}
}
return true;
}
let nextNumArr;
let m = n;
do{
let nextNum = m+1
m=nextNum
let nextNumStrg = nextNum.toString();
nextNumArr = nextNumStrg.split('')
console.log(compareArr(nArr, nextNumArr))
}
while(compareArr(nArr, nextNumArr) == false)
console.log(nextNumArr)
return parseInt(nextNumArr.join())
}
nextBigger(12);
This gives me empty array at the end;
[2,0,1,7].join() will give you '2,0,1,7', can use [2,0,1,7].join('') and get '2017'
All looks a bit complicated. How about:
const nextLarger = num => {
const numX = `${num}`.split(``).map(Number).reverse();
for (let i = 0; i < numX.length; i += 1) {
if ( numX[i] > numX[i + 1] ) {
numX.splice(i, 2, ...[numX[i+1], numX[i]]);
return +(numX.reverse().join(``));
}
}
return num;
};
const test = [...Array(100)].map(v => {
const someNr = Math.floor(10 + Math.random() * 100000);
const next = nextLarger(someNr);
return `${someNr} => ${
next === someNr ? `not possible` : next}`;
}).join('\n');
document.querySelector(`pre`).textContent = test;
<pre></pre>
See also
function nextbig(number) {
let nums = []
number.toString().split('').forEach((num) => {
nums.push(parseInt(num))
})
number = nums
n = number.length
for (var i = n - 1; i >= 0; i--) {
if (number[i] > number[i - 1])
break;
}
if (i == 1 && number[i] <= number[i - 1]) {
return 'No greater possible'
}
let x = number[i - 1];
let smallest = i;
for (let j = i + 1; j < n; j++) {
if (number[j] > x &&
number[j] < number[smallest])
smallest = j;
}
let temp = number[smallest];
number[smallest] = number[i - 1];
number[i - 1] = temp;
x = 0
for (let j = 0; j < i; j++)
x = x * 10 + number[j];
number = number.slice(i, number.length + 1);
number.sort()
for (let j = 0; j < n - i; j++)
x = x * 10 + number[j];
return x
}
console.log(nextbig(12))
console.log(nextbig(513))
console.log(nextbig(2017))
In compareArr you are deleting elements as you find them, which is correct to do, to make sure duplicates actually occur twice etc. However, that also deletes the elements from nextNumArr in the calling context, because the array is passed by reference and not by value. You need to do a manual copy of it, for example like this: compareArr(nArr, [...nextNumArr]).
I have used a different approach, first I search for all possible combinations of the given numbers with the permutator function. This function returns an array of possible numbers.
Then I sort this array of combinations and look for the index of the given number in the main function.
Once I have this index I return the position before the given number.
function nextbig(num){
function permutator(inputArr){
let result = [];
const permute = (arr, m = []) => {
if (arr.length === 0) {
result.push(m)
} else {
for (let i = 0; i < arr.length; i++) {
let curr = arr.slice();
let next = curr.splice(i, 1);
permute(curr.slice(), m.concat(next))
}
}
}
permute(inputArr)
return result;
}
let arrNums = num.toString().split('')
let combinations = permutator(arrNums).map(elem => parseInt(elem.join("")))
combinations.sort((a, b) => {
return b - a
})
let indexOfNum = combinations.findIndex(elem => elem === num)
let nextBigIndex = indexOfNum <= 0 ? 0 : indexOfNum - 1
return (combinations[nextBigIndex])
}
console.log(nextbig(12))
console.log(nextbig(517))
console.log(nextbig(2017))

strings flipping

the original input ?
huhhhgghghjhjhjhjhjhjhjhjhjhjhjhjhjjhjhjhhjhjhjhjhjjhhjjhhhjhjhjhjhjhjhjhjhjjh hjgjghhjgvjghvjgh hah bhjbh hb hb h
UPDATED QUESTION
const scrambled = list => {
let storage = [];
let scrambledWords = list[1];
let letterCount = 0;
let dict = list[0].split(',').reduce((obj,ele) =>{
obj[ele] = true;
return obj;
},{});
for(let i = 0; i< word;i++){
if(i === Object.keys(dict[1])){
}
}
return storage.join()
};
One approach would be to store the indexes of the characters at original string as properties to an object, where value is set to character. Iterate object properties to create, set or replace rearranged string to original input characters indexes.
let str = "Hello World";
function scramble(s) {
const indexes = [];
const len = Array.from({
length: s.length
}, (_, index) => index);
let scrambledString = "";
do {
let index = Math.floor(Math.random() * len.length);
let curr = len.splice(index, 1)[0];
indexes.push(curr);
scrambledString += s[curr];
} while (len.length);
return {scrambledString, indexes};
}
function unscramble(s, arr) {
let res = "";
for (let i = 0; i < arr.length; i++) {
res += s[arr[arr.indexOf(i)]];
}
return res
}
let scrambled = scramble(str);
console.log(scrambled.scrambledString);
let unscrambled = unscramble(str, scrambled.indexes);
console.log(unscrambled);

Categories

Resources