Javascript Generate Multidimensional array of 2 sizes - javascript

I cannot figure out the best way to dynamically generate a multidimensional array with 2 different sizes.
We have a UI that requires a row of 4 items, then 3. This pattern would repeat until the content in the array has been spent.
This is essentially what I need to do:
// Convert
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
// to
const rows [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10, 11], [12, 13, 14]];
This is what I currently have, it is only converting the arrays to 4 each.
const buildRows = (arr, length) => arr.reduce((rows, val, i) => (
i % length == 0 ? rows.push([val]) : rows[rows.length-1].push(val)
) && rows, []);
Thank you in advance for the help.

The following solution will mutate (empty) the input array array:
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
let result = [], i = 0;
while(array.length) { // while there still items in array (array is continually getting shrunk untill it is emptied (array.length === 0))
result.push(array.splice(0, i++ % 2? 3: 4)); // cut the first 3 or 4 numbers depending on the index of the cut i (if i is pair, then cut 4, else, cut 3) and then push the cut-out items into the result array
}
console.log(result);
If you don't want to mutate it, then use slice instead of splice, but you'll have to provide the start index of the cut:
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
let result = [], i = 0, next = 0; // next will be the index from which the cut will start
while(next < array.length) { // there is still items to cut
let itemsToCut = i % 2? 3: 4; // determine how many items we are going to cut
result.push(array.slice(next, next + itemsToCut)); // cut the items between next and next + itemsToCut
next += itemsToCut; // increment next by the number of cut-out items so it will point to the next item
i++;
}
console.log(result);

I suggest a more self-documenting generator solution where even & odd row-sizes are not hardcoded but supplied via arguments:
function* reshape(array, ...rows) {
let i = 0;
while (true) for (let row of rows) {
if (i >= array.length) return;
yield array.slice(i, i += row);
}
}
// Example:
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
for (let row of reshape(array, 4, 3)) console.log(row);
A true generator purist would simplify reshape by first introducing a repeat generator:
function* repeat(iterable) {
while (true) yield* iterable;
}
function* reshape(array, ...rows) {
let i = 0;
for (let row of repeat(rows)) {
if (i >= array.length) break;
yield array.slice(i, i += row);
}
}
// Example:
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
for (let row of reshape(array, 4, 3)) console.log(row);

You can achieve that using Array#reduce, a pointer to the last place, and a step variable that alternates between 3 and 4:
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let last = 0;
let step = 0;
const result = array.reduce((r, num, i) => {
if(i === last + step) { // when the previous sub array is full
r.push([]); // add another sub array
last = i; // mark the start index of the current sub array
step = step === 4 ? 3 : 4; // alternate the step
}
r[r.length - 1].push(num); // push the number to the last sub array
return r;
}, []);
console.log(result);

Straighfoward and easy-to-read solution:
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const r = [];
let chunk = [];
let l = 4;
array.forEach((el, i) => {
if (chunk.length < l) chunk.push(el);
if (chunk.length === l) {
r.push(chunk); chunk = [];
l = ( l === 4 ) ? 3 : 4;
}
})
console.log(r)

Yet another solution. Clearly everyone is having a good time with this one.
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
function divide(array, idx, num, result)
{
if(array.length <= idx) return result;
result.push(array.slice(idx,idx+num));
return divide(array, idx+num, num === 4 ? 3 : 4, result);
}
console.log(divide(array, 0, 4, []));

We can think of it as slicing elements from the array in a loop. It's just that we need to alternate between 4 and 3 instead of a constant value to slice.
We can parameterize alternating values by passing them in a function instead of hardcoding it in the solution like below:
Use Array##slice and
Just swap current and next like this by using destructuring assignment to achieve the solution.
Sub array sizes(4,3) can be modified outside actual logic or can be passed in a function to have flexible solution.
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
function TransformArray(array, current, next) {
let start = 0,
ans = [];
while (start < array.length - 1) {
ans.push(array.slice(start, start + current));
start += current;
[current, next] = [next, current]; //swap the count of array size
}
return ans;
}
console.log(TransformArray(array, 4, 3));
console.log(TransformArray(array, 3, 3));

Here's kind of a different way of doing this, I'm expanding a bit to allow you to arbitrarily pass array lengths, this allows the PM to change their mind any time and it isn't a big deal.
This could be cleaned up a bit, I wanted to leave it more verbose to make it easier to read.
// Setup the function getting in:
// an array
// first array's length
// second array's length
const arrayParser = (inArr,arr1len,arr2len) => {
// Create a new array.
let outArr = [];
// Basic forEach is basic, we need the value and the index.
inArr.forEach((val,idx) => {
// If the index's modulus of the total of the two array lengths is:
// 0 OR the first array's length
// Push a new empty array.
if (idx%(arr1len+arr2len)===0 || idx%(arr1len+arr2len)===arr1len) {
// Create a new array with the current value
outArr.push([]);
}
// Push the value to the last array in the out multidimensional array
outArr[outArr.length-1].push(val);
});
// You got it.. return the array.
return outArr;
};
// Single Dimensional Array
const singleArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
// Parse it.
// Expects:
// A Single Dimensional Array
// Length of the first array
// Length of the second array
console.log(arrayParser(singleArray,10,4));
console.log(arrayParser(singleArray,2,4));
console.log(arrayParser(singleArray,3,4));
console.log(arrayParser(singleArray,4,3));
console.log(arrayParser(singleArray,1,2));
This works, because you know the length of each of the inner arrays, so you don't really need to figure out anything.
Here's a 4,3 set broken out.
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
Push a new array at 0 and 4.
4+3
index total Modulus
0 % 7 = 0 <-- push [], push 1
1 % 7 = 1 <-- push 2
2 % 7 = 2 <-- push 3
3 % 7 = 3 <-- push 4
4 % 7 = 4 <-- push [], push 5
5 % 7 = 5 <-- push 6
6 % 7 = 6 <-- push 7
7 % 7 = 0 <-- push [], push 8
8 % 7 = 1 <-- push 9
9 % 7 = 2 <-- push 10
10 % 7 = 3 <-- push 11
11 % 7 = 4 <-- push [], push 12
12 % 7 = 5 <-- push 13
13 % 7 = 6 <-- push 14
Returns
[[1,2,3,4],[5,6,7],[8,9,10,11],[12,13,14]]

It ain't pretty and as much as I try to write functional code, it's pretty easy with a while loop...
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const newArray = [];
let i = 0;
while (i < array.length) {
let four = array.slice(i, i + 4)
if (!(four.length > 0)) {
break;
}
newArray.push(four)
i += 4;
let three = array.slice(i, i + 3);
if (!(three.length > 0)){
break;
}
newArray.push(three);
i += 3;
}
return newArray

Related

How do I Replace the elements in the Array and assign it zero in javascript?

Write a function squareWave(arr) that takes in the following array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], and starts replacing the numbers, one by one, with zeroes, until it reaches a multiple of 5. From that point onwards, start replacing the numbers with 1s, until you reach the next multiple of 5.
Then, from that point onwards, start replacing with 0s again, then 1s again,and so on until you reach the end of the array.
My code is not working Anybody can help me?
let input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
function squareWave(arr) {
let zeros = true;
let output = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] % 5) {
arr[i] = 0;
} else if (arr[i] !== 5) {
arr[i] = 1;
}
}
console.log(arr)
}
Output should be=[0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1]
You are not keeping track if the current entry should be a 0 or 1. Also, you are not using variables zeros and output
Instead of a boolean, you can keep a 0 or 1 in the variable zeros and flip the value when the mod of 5 equals zero.
if (arr[i] % 5 === 0) {
Then for every iteration write the value of zeros
let input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
function squareWave(arr) {
let zeros = 0;
let output = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] % 5 === 0) {
zeros = 1 - zeros
}
output[i] = zeros;
}
return output;
}
console.log(squareWave(input));
Or in short:
let input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
let res = input.map(i => Math.abs(Math.floor(i / 5) % 2))
console.log(res)
You can use Array's map function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
let control = 0;
const list = input.map(value => {
if (value % 5 === 0) {
control = control === 0 ? 1 : 0;
}
return control;
});
console.log(list);
As this is clearly a homework question, I won't give you the answer, but suggest your next steps. You actually almost have the idea of the answer, but you didn't actually implement it.
I'm assuming your current code output looks like [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ...]
At the beginning of your code you have a boolean variable called zeros. What do you think this boolean is for, and why haven't you used it in your loop?
So your current code is outputting 1 when the value is a multiple of 5, but then it forgets immediately after. How might you fix that?
To replace an element in an array:
Use the indexOf() method to get the index of the element.
Use bracket notation to change the value of the element at the specific index.
The value of the array element will get updated in place.
const arr = ['a', 'b', 'c'];
const index = arr.indexOf('a'); // it will give you 0
if (index !== -1) {
arr[index] = 'z';
}
console.log(arr); // it will give you ['z', 'b', 'c']

Get every second element of array with array methods

for learning purposes I want to get every second element of an array. I succeeded with a for loop:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function filterEverySecond(arr) {
let everySecondEl = [];
for (let i = 0; i < arr.length; i += 2) {
everySecondEl.push(arr[i]);
}
return everySecondEl;
}
console.log({
numbers,
result: filterEverySecond(numbers)
});
Now I want to achieve the same without a for loop, but by using array methods (forEach, filter, map or reduce). Can anyone recommend which method would be best here?
you can do it easily with filter
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const filtered = numbers.filter((_, i) => i % 2 === 0)
console.log(filtered)
you just filter out the elements that have a odd index
You can use filter and check if the index of the current array element is divisible by 2:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log({
numbers,
result: numbers.filter((_, index) => index % 2 === 0)
});
You can use filter for index.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log({
numbers,
result: numbers.filter((n,i)=>i%2==0)
});
You could use a for each loop like so to get the same desired output:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = [];
numbers.forEach(number => {
if (number % 2 != 0) {
result.push(number);
}
});
console.log(numbers);
console.log(result);
The modulus operator returns the remainder of the two numbers when divided. For example: 1 % 2 will return 1 as the remainder. So in the if statement we are checking if the number is not divisible by 2.

latest elements in array not found? codewars kata

I'm solving the following kata:
Given an input of an array of digits, return the array with each digit incremented by its position in the array: the first digit will be incremented by 1, the second digit by 2, etc. Make sure to start counting your positions from 1 (and not 0).
Your result can only contain single digit numbers, so if adding a digit with it's position gives you a multiple-digit number, only the last digit of the number should be returned.
Notes:
return an empty array if your array is empty
arrays will only contain numbers so don't worry about checking that
Examples
[1, 2, 3] --> [2, 4, 6] # [1+1, 2+2, 3+3]
[4, 6, 9, 1, 3] --> [5, 8, 2, 5, 8] # [4+1, 6+2, 9+3, 1+4, 3+5]
# 9+3 = 12 --> 2
My code:
const incrementer = (arr) => {
if (arr === []) {
return []
}
let newArr = []
for (let i = 0; i <= arr.length; i++) {
let result = arr[i] + (i + 1)
newArr.push(result)
if (newArr[i] > 9 ) {
let singleDigit = Number(newArr[i].toString().split('')[1])
newArr.push(singleDigit)
}
}
const filteredArr = newArr.filter(el => el >= 0 && el <= 9)
return filteredArr
}
I can't seem to pass the latest test case, which is the following:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8]), [2, 4, 6, 8, 0, 2, 4, 6, 8, 9, 0, 1, 2, 2]
I keep getting back the whole correct array up until the second 0, after which the other numbers, 1,2,2 are missing from the solution. What am I doing wrong?
The problem in your code is that the filter only runs at the end, and so when you have done a double push in one iteration (once with the value that has more than one digit, and once with just the last digit), the next iteration will no longer have a correct index for the next value that is being pushed: newArr[i] will not be that value.
It is better to correct the value to one digit before pushing it to your new array.
Moreover, you can make better use of the power of JavaScript:
It has a nice map method for arrays, which is ideal for this purpose
Use modulo arithmetic to get the last digit without having to create a string first
Here is the proposed function:
const incrementer = (arr) => arr.map((val, i) => (val + i + 1) % 10);
console.log(incrementer([1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8]));
... so if adding a digit with it's position gives you a multiple-digit number, only the last digit of the number should be returned.
So if the number is 12, it expects only 2 to be added to the array.
So your code should be:
if (newArr[i] > 9)
{
newArr[i] = newArr[i] % 10; // remainder of newArr[i] / 10
}
const incrementer = (arr) => {
if (arr.length === 0) { // CHANGE HERE
return [];
}
let newArr = []
for (let i = 0; i <= arr.length; i++) {
let result = arr[i] + (i + 1)
newArr.push(result)
if (newArr[i] > 9 ) {
newArr[i] = newArr[i] % 10; // CHANGE HERE
}
}
const filteredArr = newArr.filter(el => el >= 0 && el <= 9)
return filteredArr
}
console.log(incrementer([2, 4, 6, 8, 0, 2, 4, 6, 8, 9, 0, 1, 2, 2]));
console.log(incrementer([1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8]));
Please see below code.
const incrementer = arr => {
if (arr === []) {
return [];
}
let newArr = [];
for (let i = 0; i < arr.length; i++) {
let result = arr[i] + (i + 1);
// newArr.push(result);
if (result > 9) {
let singleDigit = Number(result.toString().split("")[1]);
newArr.push(singleDigit);
} else {
newArr.push(result);
}
}
// const filteredArr = newArr.filter(el => el >= 0 && el <= 9);
return newArr;
};
console.log(incrementer([1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8]))
const incrementer = (arr) => {
if (arr === []) {
return []
}
return arr.map((number, index) => (number + index + 1) % 10);
}
Doing the needed additions in (number + index + 1) and % 10 operation will get the last digit.

JS Number of occurences in a sequence is a prime number

I have two arrays (X and Y) and I need to create array Z that contains all elements from array X except those, that are present in array Y p times where p is a prime number.
I am trying to write this in JS.
For Example:
Array X:
[2, 3, 9, 2, 5, 1, 3, 7, 10]
Array Y:
[2, 1, 3, 4, 3, 10, 6, 6, 1, 7, 10, 10, 10]
Array Z:
[2, 9, 2, 5, 7, 10]
So far I have this:
const arrX = [2, 3, 9, 2, 5, 1, 3, 7, 10]
const arrY = [2, 1, 3, 4, 3, 10, 6, 6, 1, 7, 10, 10, 10]
const arrZ = []
const counts = [];
// count number occurrences in arrY
for (const num of arrY) {
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
// check if number is prime
const checkPrime = num => {
for (let i = 2; i < num; i++) if (num % i === 0) return false
return true
}
console.log(counts[10]);
// returns 4
Any hint or help appreciated. Thanks!
You're on the right track. counts should be an object mapping elements in arrY to their number of occurrences. It's easily gotten with reduce.
The prime check needs a minor edit, and the last step is to filter arrX. The filter predicate is just a prime check on the count for that element.
// produce an object who's keys are elements in the array
// and whose values are the number of times each value appears
const count = arr => {
return arr.reduce((acc, n) => {
acc[n] = acc[n] ? acc[n]+1 : 1;
return acc;
}, {})
}
// OP prime check is fine, but should handle the 0,1 and negative cases:
const checkPrime = num => {
for (let i = 2; i < num; i++) if (num % i === 0) return false
return num > 1;
}
// Now just filter with the tools you built...
const arrX = [2, 3, 9, 2, 5, 1, 3, 7, 10]
const arrY = [2, 1, 3, 4, 3, 10, 6, 6, 1, 7, 10, 10, 10]
const counts = count(arrY);
const arrZ = arrX.filter(n => checkPrime(counts[n]));
console.log(arrZ)

lodash : how to loop with between a start value and end value

I've a for loop in javascript shown below. How to convert it to lodash for loop?
In such scenarios using lodash is advantageous over javascript for loop?
I've not used lodash much. Hence please advice.
for (var start = b, i = 0; start < end; ++i, ++start) {
// code goes here
}
You can use lodash range
https://lodash.com/docs/4.17.4#range
_.range(5, 10).forEach((current, index, range) => {
console.log(current, index, range)
})
// 5, 0, [5, 6, 7, 8, 9, 10]
// 6, 1, [5, 6, 7, 8, 9, 10]
// 7, 2, [5, 6, 7, 8, 9, 10]
// 8, 3, [5, 6, 7, 8, 9, 10]
// 9, 4, [5, 6, 7, 8, 9, 10]
// 10, 5, [5, 6, 7, 8, 9, 10]
I will imagine that b = 3 and end = 10 if I run your code and print the variables here is what I will get:
var b = 3;
var end = 10;
for (var start = b, i = 0; start < end; ++i, ++start) {
console.log(start, i);
}
> 3 0
> 4 1
> 5 2
> 6 3
> 7 4
> 8 5
> 9 6
To perform this with lodash (or underscore) I will first generate an array with range then iterate over it and gets the index on each iteration.
Here is the result
var b = 3;
var end = 10;
// this will generate an array [ 3, 4, 5, 6, 7, 8, 9 ]
var array = _.range(b, end);
// now I iterate over it
_.each(array, function (value, key) {
console.log(value, key);
});
And you will get the same result. The complexity is the same as the previous one (so no performance issue).
It seems there is no lodash way for writing loose for loops (those not iterating over a collection), but here is a simplified version of it:
for (var i = 0; i < end - b; i++) {
var start = i + b;
// code goes here
}

Categories

Resources