Creating a multi-dimensional array in JavaScript with two different sizes

I'm struggling to find the best way to create a multi-dimensional array with varying sizes dynamically.

Our user interface requires a pattern where there are rows of 4 items followed by rows of 3 items. This pattern should continue until all contents in the array have been used up.

This is essentially what I am trying to achieve:

// 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]];

The current code I have only converts the arrays into groups of 4 elements each.

 const buildRows = (arr, length) => arr.reduce((rows, val, i) => (
  i % length == 0 ? rows.push([val]) : rows[rows.length-1].push(val)
) && rows, []);

I appreciate any help or guidance on how to achieve this. Thank you!

Answer №1

The solution provided below will modify the contents of 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) {                          // The loop continues as long as there are items in the array (the array size decreases with each iteration until it is empty)
  result.push(array.splice(0, i++ % 2 ? 3 : 4)); // Extract the first 3 or 4 numbers based on the value of index i (if i is even, cut 4 numbers; if odd, cut 3), then add them to the result array
}

console.log(result);

If you prefer not to alter the original array, you can utilize slice instead of splice, but specify the starting index for cutting:

const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];

let result = [], i = 0, next = 0;                      // 'next' indicates the index from which cutting begins
while(next < array.length) {                           // Loop while there are still items to be cut
  let itemsToCut = i % 2 ? 3 : 4;                        // Decide how many items to cut
  result.push(array.slice(next, next + itemsToCut));   // Cut items between 'next' and 'next + itemsToCut'
  next += itemsToCut;                                  // Increment 'next' by the number of cut-out items to point to the next item
  i++;
}

console.log(result);

Answer №2

Here is a more intuitive approach to generating a new array where the sizes of even and odd rows are determined by arguments provided:

function* generateNewArray(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 generateNewArray(array, 4, 3)) console.log(row);

To further refine the generateNewArray generator, we can start by implementing a simple repeat generator:

function* repeat(iterable) {
  while (true) yield* iterable;
}

function* generateNewArray(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 generateNewArray(array, 4, 3)) console.log(row);

Answer №3

To achieve this task, utilize the Array#reduce method along with keeping track of the last position and a variable called step that toggles 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) { // check if previous sub-array is full
    r.push([]); // add new sub-array
    
    last = i; // mark current sub-array start index
    
    step = step === 4 ? 3 : 4; // alternate step value
  }
  
  r[r.length - 1].push(num); // push number to last sub-array
  
  return r;
}, []);

console.log(result);

Answer №4

Simple and clear-cut solution:

const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];

const finalArray = [];
let chunk = [];
let limit = 4;

array.forEach((element, index) => {
  if (chunk.length < limit) chunk.push(element);
  if (chunk.length === limit) {
    finalArray.push(chunk); 
    chunk = [];
    limit = (limit === 4) ? 3 : 4;
  }
})

console.log(finalArray)

Answer №5

Here's another clever solution that seems to be generating a lot of excitement.

const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];

function splitArray(array, index, count, result)
{
  if(array.length <= index) return result;
  result.push(array.slice(index,index+count));
  return splitArray(array, index+count, count === 4 ? 3 : 4, result);
}


console.log(splitArray(array, 0, 4, []));

Answer №6

Consider the analogy of slicing elements from an array in a loop, with a twist of alternating between 4 and 3 instead of using a constant value for the slice operation. To make this process more dynamic, we can parameterize the alternating values by passing them as arguments to a function rather than hardcoding them within the solution code:

  1. Utilize Array##slice method
  2. Implement a switch between current and next counts using destructuring assignment
  3. Adjust sub-array sizes (4,3) externally or incorporate flexibility by passing them as parameters to a function.

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));

Answer №7

Here's a unique approach to handling arrays where you can dynamically change the lengths of the inner arrays without much hassle.

Although the code could be more concise, I've kept it verbose for better readability.

// Defining a function that takes in:
//     an array
//     length of the first array
//     length of the second array
const arrayParser = (inArr,arr1len,arr2len) => {
    // Creating a new array.
    let outArr = [];
    // Using forEach loop to iterate over input array with index.
    inArr.forEach((val,idx) => {
        // Checking if the current index should start a new sub-array based on modulo operations.
        if (idx%(arr1len+arr2len)===0 || idx%(arr1len+arr2len)===arr1len) {
            // Adding a new empty array when needed.
            outArr.push([]);
        }
        // Appending value to the last sub-array in the output multidimensional array.
        outArr[outArr.length-1].push(val);
    });
    // Returning the resulting array.
    return outArr;
};

// Sample 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];
// Testing different configurations
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 method doesn't require calculating indexes as long as you know the lengths of the interior arrays beforehand.

Here's how a 4,3 setup plays out:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

New arrays at indices 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

Result:

[[1,2,3,4],[5,6,7],[8,9,10,11],[12,13,14]]

Answer №8

Despite its lack of elegance, I find myself resorting to a while loop when attempting to craft functional code...

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const updatedNumbers = [];

let index = 0;
while (index < numbers.length) {
  let sectionFour = numbers.slice(index, index + 4)
  if (!(sectionFour.length > 0)) {
    break;
  }
  updatedNumbers.push(sectionFour)
  index += 4;
  let sectionThree = numbers.slice(index, index + 3);
  if (!(sectionThree.length > 0)){
    break;
  }
  updatedNumbers.push(sectionThree);
  index += 3;
}

return updatedNumbers

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Changing an object received as a prop in Vue.js

Is it acceptable to mutate values in a prop when passing an Object reference? In the process of developing a web application that involves passing numerous values to a component, I am exploring the most efficient method of handling value passing between c ...

The PHP table fails to show up on the screen

I've implemented a PHP script that connects to a MySQL database and is supposed to generate an HTML table. To achieve real-time updates, I've set up a long-polling AJAX script that polls the PHP script every second. Although everything seems to b ...

I encountered a 404 error when attempting to execute the "npm publish" command

While attempting to publish a package to the npm registry, an error is encountered after running the command npm publish. npm WARN prepublish-on-install As of npm@5, `prepublish` scripts are deprecated. npm WARN prepublish-on-install Use `prepare` for buil ...

Using Redux with Next.js to implement getStaticPaths

Can someone help me understand how to implement getStaticPaths in conjunction with Redux in Next.js? I'm currently using next-redux-wrapper to manage my content, but I am encountering issues when trying to display the data. Below is a snippet of my ...

Using object bracket notation in TypeScript to retrieve values from props with the help of string interpolation

I encountered an issue in my code while attempting to utilize a variable within my TSX component. This problem arises due to the dynamic props being passed into the component, which are always a string that matches one of four keys in the "characters" obje ...

Tips for adding a new column to a website

My goal is to inject some custom HTML and CSS into YouTube in order to create a column on the right side that shifts all content towards the left. Essentially, I am trying to replicate the functionality of the Inspect Tool in Chrome. I am working on a Chr ...

I am retrieving data from a service and passing it to a component using Angular and receiving '[object Object]'

Searching for assistance with the problem below regarding my model class. I've attempted various approaches using the .pipe.map() and importing {map} from rxjs/operators, but still encountering the error message [object Object] export class AppProfile ...

"Implementing a conditional statement in JS / JQuery without the need to

I'm interested in finding out if it's possible for a function's conditional statement to display the result whenever the argument is true, without needing to call the function again. Here is an example of such a statement: if($('#a&ap ...

Display more/hide less form using div elements in a NextJS project

Looking to create a hidden block of amenities on my hotel website that can be expanded and collapsed with buttons in NextJS using tailwind-css. How can I achieve this functionality? Example 1: https://i.stack.imgur.com/BbrUj.png Example-2: https://i.stac ...

Adding a div to the preceding div based on matching IDs in AngularJS

Here is a representation of my layout in HTML: <div ng-repeat="message in messages"> <div ng-class="{'messages messages--sent': userId == message.id, 'messages messages--received': userId != me ...

Challenges with Scaling HTML5 Video onto Canvas

Attempting to extract a frame from an html5 video to generate a thumbnail, but encountering peculiar outcomes when the image is rendered onto canvas. The issue lies in the fact that the canvas displays only a greatly magnified portion of the video! Refer ...

Please provide several input fields with identical 'name' attributes for submission

I'm encountering an issue with a form where multiple input fields (text) share the same name attribute. On the backend, I am utilizing node.js and Mongoose for a POST method. Below is a snippet of the code: if(existingFruit) { Fruit.findOneA ...

Absolute positioned content causing unexpected spacing on top of relative positioned content

I've been experimenting with a fantastic technique by Chris Coyier for implementing full page video backgrounds with content scrolling over the video. However, I've encountered an issue where there's an unexpected gap to the right in Windows ...

Utilize the useRef hook in React to enable copying text to the clipboard

Looking to implement a copy to clipboard functionality in React using the useRef hook? Want to accomplish this without relying on any additional libraries? Take a look at my code snippet below. Currently, I'm encountering an error stating myRef.curren ...

Dynamically linking tabbable tabs is a useful technique that allows for

I have been working on an app that organizes websites into groups displayed as tabs in a tabbable navigator using Twitter Bootstrap. The idea is that each time a new group is added, a new tab should appear. Currently, this is how it looks: The functionali ...

JavaScript heap running out of memory after upgrading from Angular 11 to versions 12, 13, or 14

I need assistance with resolving a JS heap out of memory issue that has been occurring when trying to start the local server ever since migrating from Angular 11 to Angular 12 (or 13 or 14, all versions tested with the same problem). This occurs during th ...

Modifying the structure of serialized data

After serializing a JS form, the data looks like this: .....&xx=xxx&otherError=&input=SMS&message=sdfgs&...... Can anyone provide guidance on how to replace the value of message with the content of a textarea before making an ajax cal ...

Click the button to save the text to your clipboard with a customized

Can anyone suggest a method for duplicating div text using JavaScript while preserving the style attributes (italics, font family, size, etc.)? My goal is to paste the copied text into Word and have it maintain the same appearance as on the webpage. For e ...

The Quirks of jQuery's .load() Method

On my website, I am incorporating a basic jQuery script to load content from one part of a webpage into the 'display container' on the same page. The content being loaded consists of multiple divs enclosed within an outer <div> that is hid ...

Dealing with a passed EJS variable in string form

When working with passed data in ejs, I usually handle it like this and it works perfectly: let parsed_json = JSON.parse('<%-JSON.stringify(passed_data)%>'); However, I encountered a problem when trying to dynamically pass a string variabl ...