How to replace spaces whilst adding new elements? - javascript

I have a stepped array of elements that is filled as follows:
class Funnel{
constructor() {
this.funnelContents = [];
this.layer = 0;
}
get content() {
return this.funnelContents;
}
fill(...nums) {
let index, startIndex = 0;
for(let i = 0; i < this.funnelContents.length; i++){
while ((index = this.funnelContents[i].indexOf(' ', startIndex)) > -1 && nums.length > 0) {
this.funnelContents[i][index] = nums.shift();
startIndex = index + 1;
}
}
return nums
.splice(0, 15 - this.funnelContents.reduce((count, row) => count + row.length, 0))
.filter(num => num < 10)
.reduce((arr, num) => {
if (this.funnelContents.length) {
this.funnelContents[this.funnelContents.length - 1] = this.funnelContents[this.funnelContents.length - 1].filter(char => char !== ' ');
if ((this.funnelContents[this.layer] || []).length !== this.funnelContents[this.layer - 1].length + 1) {
this.funnelContents[this.layer] = [...(this.funnelContents[this.layer] || []), num];
} else {
this.layer++;
this.funnelContents[this.layer] = [num];
}
}
else {
this.layer++;
this.funnelContents = [...this.funnelContents, [num]];
}
}, []);
}
toString() {
let str = '', nums = '', spacesCount = 1;
for(let i = 5; i > 0; i--){
str += '\\';
for(let j = 0; j < i; j++) {
if (this.funnelContents[i - 1] !== undefined) {
if (this.funnelContents[i - 1][j] !== undefined) {
nums += this.funnelContents[i - 1][j];
} else {
nums += ' ';
}
} else {
nums += ' ';
}
}
str += nums.split('').join(' ') + '\/\n' + ' '.repeat(spacesCount);
nums = '';
spacesCount++;
}
return str.substring(0, str.length - 6);
}
}
let funnel1 = new Funnel();
let funnel2 = new Funnel();
let funnel3 = new Funnel();
let funnel4 = new Funnel();
let funnel5 = new Funnel();
let funnel6 = new Funnel();
let funnel7 = new Funnel();
funnel1.fill(5,4,3,4,5,6,7,8,9,3,2,4,5,6,7,5,6,7,8); //15 elements will be added, the rest are ignored
funnel2.fill(5,4,3,4,5,6,7,8);
funnel2.fill(9,3,2,4,5,6,7);
funnel3.fill(' ');
funnel3.fill(1,5,7);
funnel4.fill(1,2,3);
funnel4.fill(' ');
funnel4.fill(3,4,5);
funnel5.fill(1);
funnel5.fill(' ', ' ', ' ');
funnel5.fill(8,2,1);
funnel6.fill(' ',' ');
funnel6.fill(1,8,2,1);
funnel7.fill(' ',' ',' ',' ',' ');
funnel7.fill(1,8,2,1);
console.log(funnel1.toString()); // the output is as expected.
console.log(funnel2.toString()); // the same result
console.log(funnel3.toString()); // expected [ [1], [5,7] ] and it really is
console.log(funnel4.toString()); // expected [ [1], [2,3], [3,4,5] ] and it really is
console.log(funnel5.toString()); // expected [ [1], [8,2], [1] ] and it really is
console.log(funnel6.toString()); // expected [ [1], [8,2], [1] ] but got [ [], [1,8], [2], [1] ]
console.log(funnel7.toString()); // nothing is changed
Here you can see that at the very beginning of the function fill a cycle was written to insert elements that came to the input instead of spaces. I added spaces artificially, in fact, there is another function that adds them. But:
1) For some reason this does not always work, for an array in the example it does not work. With a simpler space search algorithm, it also does not work properly:
for (let i = 0; i < this.funnelContents.length; i++) {
for (let j = 0; j < this.funnelContents[i].length; j++) {
if(this.funnelContents[i][j] === ' '){
this.funnelContents[i][j] = nums.shift();
}
}
}
2) It looks very cumbersome and I would like to do something similar more elegantly. I was thinking of two for loops to find elements I need, but I still hope that I can implement insertion instead of spaces inside reduce function.

You could take a single loop and slice substrings with increasing length.
function funnel(array) {
var i = 0,
l = 0,
result = [];
while (i < array.length) result.push(array.slice(i, i += ++l));
return JSON.stringify(result);
}
console.log(funnel([1]));
console.log(funnel([1, 2]));
console.log(funnel([1, 2, 3]));
console.log(funnel([1, 2, 3, 4]));
console.log(funnel([1, 2, 3, 4, 5]));
console.log(funnel([1, 2, 3, 4, 5, 6]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]));
console.log(funnel([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
As I understand the comment, you have an array in the given style with incrementing count, but some elements are spaces and this elemenst should bereplaced with the given data.
In this case, a nested loop for getting the result set right and another index for getting the value from the data array should work.
class Funnel {
constructor() {
this.funnelContents = [];
}
get content() {
return this.funnelContents;
}
fill(...nums) {
var i = 0,
j = 0,
l = 1,
k = 0,
target = this.funnelContents;
while (k < nums.length) {
if (!target[i]) target.push([]);
if ([undefined, ' '].includes(target[i][j])) target[i][j] = nums[k++];
if (++j === l) {
if (++i > 4) break; // max 15 elements in result set
j = 0;
l++;
}
}
}
}
var funnel = new Funnel;
funnel.fill(' ', ' ', ' ', ' ');
console.log(JSON.stringify(funnel.content));
funnel.fill(1, 2, 3, 4, 5, 6, 7, 8, 9);
console.log(JSON.stringify(funnel.content));
funnel.fill(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
console.log(JSON.stringify(funnel.content));

Related

Loops & Control Flow

When I run this I can't seem to get the rest of the values.
Write a function mergingTripletsAndQuints which takes in two arrays as arguments. This function will return a new array replacing the elements in array1 if they are divisible by 3 or 5. The number should be replaced with the sum of itself added to the element at the corresponding index in array2.
function mergingTripletsAndQuints(array1, array2) {
let result = [];
let ctr = 0;
let x = 0;
for (let i = 0; i < array1.length; i++) {
for (let j = 0; j < array2.length; j++) {
ctr = array1[i] + array2[j];
if (ctr % 3 === 0 || ctr % 5 === 0) {
result.push(ctr);
} else {
return array1[i];
}
}
}
return result;
}
console.log(mergingTripletsAndQuints([1, 2, 3, 4, 5, 15], [1, 3, 6, 7, 8, 9])); // expected log [1, 2, 9, 4, 13, 24]
console.log(mergingTripletsAndQuints([1, 1, 3, 9, 5, 15], [1, 2, 3, 4, 5, 6])); // expected log [1, 1, 6, 13, 10, 21]
It is only logging [1], [1]
I'm not sure, but I suppose there is a typo returning array1[i] in nested loop. I suppose you mean result.push(array1[i]) instead.
I think it should be something like this:
function mergingTripletsAndQuints(array1, array2) {
let result = [];
for (let i = 0; i < array1.length; i++) {
if (array1[i]% 3 === 0 || array1[i]% 5 === 0) {
result.push(array1[i] + array2[i]);
} else {
result.push(array1[i]);
}
}
return result;
}
console.log(mergingTripletsAndQuints([1, 2, 3, 4, 5, 15], [1, 3, 6, 7, 8, 9])); // expected log [1, 2, 9, 4, 13, 24]
console.log(mergingTripletsAndQuints([1, 1, 3, 9, 5, 15], [1, 2, 3, 4, 5, 6])); // expected log [1, 1, 6, 13, 10, 21]
A nested for loop is not necessary, look at this code:
function mergingTripletsAndQuints(array1, array2) {
let sum = [];
for (let i = 0; Math.max(i < array1.length, i < array2.length); i++) {
if (array1[i] % 3 == 0 || array1[i] % 5 == 0) {
sum.push(array1[i] + array2[i])
} else {
sum.push(array1[i])
}
}
return sum;
}

Count repeated numbers in array and return true (Cognitive Complexity)

I need to check if a number repeats itself at least three times in an array. How can I refactor it to decrease the Cognitive Complexity that Lint keeps complaining about.
Heres my code:
let array11 = [1, 3, 2, 3, 5, 6, 7, 8, 9, 0, 1];
function checkDuplicateNumber (array11) {
for (let i = 0; i < array11.length; i += 1) {
let sameNumberLoop = 0;
for (let i2 = i; i2 < array11.length; i2 += 1) {
if (array11[i] === array11[i2]) {
sameNumberLoop += 1;
if (sameNumberLoop >= 3) {
return true;
}
}
}
}
}
Instead of iterating multiple times, iterate just once, while counting up the number of occurrences in an object or Map:
let array11 = [1, 3, 2, 3, 5, 6, 7, 8, 9, 0, 1];
function checkDuplicateNumber (array) {
const counts = {};
for (const num of array) {
counts[num] = (counts[num] || 0) + 1;
if (counts[num] === 3) return true;
}
return false;
};
console.log(checkDuplicateNumber(array11));
console.log(checkDuplicateNumber([3, 1, 3, 5, 3]));
let array11 = [1, 3, 2, 3, 5, 6, 7, 8, 9, 0, 1]
let array22 = [1, 3, 2, 3, 5, 6, 7, 1, 9, 0, 1]
function checkDuplicateNumber(arr) {
const map = new Map()
return arr.some((v) => (map.has(v) ? (++map.get(v).count === 3) : (map.set(v, { count: 1 }), false)))
}
console.log(checkDuplicateNumber(array11))
console.log(checkDuplicateNumber(array22))

Bubblesort in javascript can't run?

Please can you tell me what is wrong to this implementation of bubble sort algorithm in JavaScript?
function bubbleSort(arr) {
var swapped;
do {
swapped = false;
for (var i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
swapped = true;
}
}
} while (swapped)
}
console.log(bubbleSort([4, 25, 1, 6, 2])); // [ 1, 2, 4, 6, 25 ]
console.log(bubbleSort([13, 1, 9, 38, 8, 3, 1])); // [ 1, 2, 4, 6, 25 ]
Your function will return undefined.You need to return arr from the function.
If you don't want to modify the original array then make a copy of original array using slice(). In the below case it doesnot matter because arrays are not stored in any variable.
function bubbleSort(arr) {
arr = arr.slice()
var swapped;
do {
swapped = false;
for (var i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
swapped = true;
}
}
} while (swapped)
return arr;
}
console.log(bubbleSort([4, 25, 1, 6, 2])); // [ 1, 2, 4, 6, 25 ]
console.log(bubbleSort([13, 1, 9, 38, 8, 3, 1])); // [ 1, 2, 4, 6, 25 ]

Have a big array of integers need to return an array that has 1 added to the value represented by the array

It is for a studying purpose. Have a big array of integers need to return an array that has 1 added to the value represented by the array.
Tried to convert the array into an integer, but after using
parseInt('9223372036854775807', 10) received 9223372036854776000, instead of 9223372036854775807
What is going wrong here?
var arr = [ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 7 ];
function upArray(arr){
var numb = arr.join('');
numb = parseInt(numb, 10);
var result = numb + 1;
console.log(result);
result = result.toString(10).split('').map(Number);
return result;
}
You are exceeding the capacity of JavaScript's number type
IEEE-754 double-precision floating point (the kind of number JavaScript uses) can't precisely represent all numbers
Beyond Number.MAX_SAFE_INTEGER + 1 (9007199254740992), the IEEE-754 floating-point format can no longer represent every consecutive integer
also you dont need to use a second argument to parseInt unless you are looking to use a different base than decimal
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
If you use the code with an array of numbers that when joined is within this limit your code will work
var arr = [ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5 ];
function upArray(arr){
var numb = arr.join('');
numb = parseInt(numb);
var result = numb + 1;
console.log(result)
result = result.toString(10).split('').map(Number);
return result;
}
console.log(upArray(arr))
As you're exceeding the MAX_SAFE_INTEGER.
If you just want to display you can go this way
var arr = [ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 7 ];
function addone(arr){
let carry = 0;
for(let i=arr.length-1; i>=0; i--){
if(i === arr.length-1) {
if( arr[i]+1 > 9){
arr[i] = 10-(arr[i] + 1);
carry = 1;
} else {
arr[i] +=1;
carry= 0;
}
}
if( i !== arr.length-1 ){
if( carry === 0) break;
if( arr[i]+1+carry > 9){
arr[i] = 10-(arr[i] + carry);
carry = 1;
} else {
arr[i] +=carry;
carry= 0;
}
}
}
if(carry === 1)
arr.unshift(1)
return arr;
}
console.log(addone(arr).join(''))
console.log(addone([1,2,9]).join(''))
console.log(addone([9,9,9]).join(''))
The value is going beyond the max number value.
Here is recursive appproch for the problem:
function upArray(arr, lastIndex){
if(lastIndex == undefined){
lastIndex = arr.length - 1;
}
if(lastIndex < 0){
return;
}
if(arr[lastIndex] == 9){
arr[lastIndex] = 0;
upArray(arr, lastIndex - 1);
}
else {
arr[lastIndex] = arr[lastIndex] + 1;
}
return arr;
}
var arr = [ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 9];
var result = upArray(arr);
console.log(result);
Another solution so you can choice =)
var arr = [9,9,9];//[ 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 7 ];
var i = arr.length;
var append = true;
while(append){
if(--i < 0){
arr.unshift(1);
break;
}
var v = arr[i];
if(++v >= 10)
v -= 10;
else
append = false;
arr[i] = v;
}
var r = arr.join('');
console.log(r);
it means the maximum range for an Intiger number has reached, here is a link
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
to solve this split the array value and add one to it and then combine then back and display the entire array as a String (don't parse it).
function upArray(arr){
var temp = arr;
var len = arr.length;
var temp2 = arr;
temp2 = temp2.slice(0,len/2).join('');
temp2 = parseInt(temp2);
temp = temp.slice(len/2).join('');
numb = parseInt(temp) +1;
if(numb.toString().length > (len/2 + len%2))
{
numb = numb.toString().slice(1);
temp2++;
}
var result = temp2.toString() + numb.toString();
console.log(result);
result = result.split('').map(Number);
return result;
}
hope it helps and have pass through every test...
As everybody would agree that the issue here is having a value that is exceeding the capacity of JavaScript's number type, we can expect that there'll be proposed workarounds like having to split the array into multiple array and work from there.
We can actually solve this on another approach. Since your representation of a number is splitting it into single digits stored as an array, and you want to perform a simple addition on it, we can observe a representation of a simple/elementary addition. The one where we add a value digit by digit from the bottom and make use of the "Carry Over" concept. We can actually do it that way.
It will look somewhat like this (A bit longer code for readability):
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var y = [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9];
var add1 = (arr) => {
var hasCarryOver = true;
for (var index = arr.length - 1; index >= 0; index--) {
if (!hasCarryOver) {
break;
}
if (arr[index] < 9) {
arr[index] = arr[index] + 1;
hasCarryOver = false;
} else {
arr[index] = 0;
}
}
if (hasCarryOver) {
arr.unshift(1);
}
return arr;
};
x = add1(x);
y = add1(y);
console.log('result x add 1', x);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 9, 0]
console.log('result y add 1', y);
// [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

How to recognize a repeating pattern in an array in javascript

If I have an array like
const arr = [1, 5, 7, 5, 13, 8, 1, 7, 3, 8, 5, 2, 1, 5, 7];
What would be the best way of finding that the array starts to repeat itself? In this instance that the first three numbers and the last three numbers are in a repeating pattern.
This is a random array, the repeating could easily start at index 365 and not necessarily from the first index.
Any ideas?
Thanks in advance
This does what you're looking for...
const arr1 = [1, 5, 7, 5, 13, 8, 1, 7, 3, 8, 5, 2, 1, 5, 7];
const arr2 = [1, 5, 7, 5, 13, 8, 1, 7, 3, 8, 5, 2, 1, 4, 7];
function patternFound(arr) {
var newArray = arr.map(function(o, i) {
if (i < arr.length - 1) {
return arr[i] + "|" + arr[i + 1];
}
})
.sort();
newArray = newArray.filter(function(o, i) {
if (i < arr.length - 1) {
return (o == newArray[i + 1]);
}
});
return newArray.length > 0;
}
console.log(patternFound(arr1));
console.log(patternFound(arr2));
Basically, it creates an array of paired elements from the first array, with a pipe delimiter (["1|5", "5|7", "7|5" etc.]), sorts it and then looks for duplicates by comparing each element to the next.
There's probably a much smaller way of doing this, but I didn't want to spend time making something that was unreadable. This does what you want and does it simply and clearly.
The first array is the one you supplied, and the second has been changed so there's no matching pattern.
You could use a single loop approach with short circuit and a hash table for found pairs like
{
"1|5": true,
"5|7": true,
"7|5": true,
"5|13": true,
"13|8": true,
"8|1": true,
"1|7": true,
"7|3": true,
"3|8": true,
"8|5": true,
"5|2": true,
"2|1": true
}
The iteration stops immediately on index 12 with the other found pair 1|5.
function check(array) {
var hash = Object.create(null);
return array.some(function (v, i, a) {
var pair = [v, a[i + 1]].join('|');
return hash[pair] || !(hash[pair] = true);
});
}
console.log(check([1, 5, 7, 5, 13, 8, 1, 7, 3, 8, 5, 2, 1, 5, 7])); // true
console.log(check([1, 5, 7, 5, 13, 8, 1, 7, 3, 8, 5, 2, 1, 3, 7])); // false
A nested loop seems the simplest approach.
Make sure to offset the nested loop to save calculations:
/**
* Takes array and returns either boolean FALSE or the first index of a pattern
*
* #param {any[]} arr
* #returns {(false | number)}
*/
function findArrayPattern(arr) {
if (arr.length < 2) {
return false;
}
for (var point1 = 0; point1 < arr.length - 2; point1++) {
var p1 = arr[point1];
var p2 = arr[point1 + 1];
for (var point2 = point1 + 2; point2 < arr.length - 1; point2++) {
var p3 = arr[point2];
var p4 = arr[point2 + 1];
if (p1 == p3 && p2 == p4) {
return point1;
}
}
}
return false;
}
//TEST
var arr = [1, 5, 7, 5, 13, 8, 1, 7, 3, 8, 5, 2, 1, 5, 7];
var pattern = findArrayPattern(arr);
if (pattern !== false) {
console.log("a pattern was found at " + pattern);
} else {
console.log("no pattern was found");
}

Categories

Resources