What is the method for generating a 2D array in JavaScript when the array's length is unknown?

I'm trying to create a 2D array that groups animals by their first letter of the alphabet. However, the output is not what I expected. I want each letter to have its own sub-array with corresponding animal names. Here's the code I tried:

function groupAnimals(animals) {
  var sort = [];
  var alphabet = 'abcdefghijklmnopqrstuvwxyz';
  var temp = [];
  
  for(var i = 0; i < alphabet.length; i++){
    for(var j = 0; j < animals.length; j++){
      if(animals[j][0] == alphabet[i]){
        temp.push(animals[j]);
      } 
    }
  }
  
  sort.push(temp);
  return sort;
}

console.log(groupAnimals(['bear', 'chicken', 'dolphin', 'cat', 'tiger']));
console.log(groupAnimals(['elephant', 'fish', 'horse', 'bird', 'flamingo', 'dog', 'ant']));

However, the output does not match my expected format. I want to achieve the following instead:

[ ['bear'], ['chicken', 'cat'], ['dolphin'], ['tiger'] ]
[ ['ant'], ['bird'], ['dog'], ['elephant'], ['fish', 'flamingo'], ['horse'] ]

My attempt to manually create sub-arrays based on the first letter of each animal proved to be inefficient and produced unexpected results. I want to achieve this using arrays and loops, but I'm struggling to figure out how to do it. Any suggestions or solutions would be greatly appreciated.

function groupAnimals(animals) {
  var sort = [];
  var alphabet = 'abcdefghijklmnopqrstuvwxyz';
  
  for(var i = 0; i < alphabet.length; i++){
    var tempArr = [];
    
    for(var j = 0; j < animals.length; j++){
      if(animals[j][0] == alphabet[i]){
        tempArr.push(animals[j]);
      } 
    }
    
    sort.push(tempArr);
  }
  
  return sort;
}

When I tried the above code, the output was:

[ ['bear'], ['chicken', 'cat'], ['dolphin'], ['tiger'], [], [], []]
[ ['ant'], ['bird'], [], ['dog'], ['elephant'], ['fish', 'flamingo'], ['horse']]

I'm looking for a more efficient solution using arrays and loops to achieve the desired output.

Answer №1

Transform the array of words into an object of arrays based on the first letter of each word, then convert it back into an array of arrays using Object.values:

const groupWords = (words) => {
  const sorted = words.slice().sort();
  const groupedObj = sorted.reduce((a, word) => {
    const key = word[0];
    if (!a[key]) {
      a[key] = [];
    }
    a[key].push(word);
    return a;
  }, {});
  return Object.values(groupedObj);
};

console.log(groupWords(['bear', 'chicken', 'dolphin', 'cat', 'tiger']));
console.log(groupWords(['elephant', 'fish', 'horse', 'bird', 'flamingo', 'dog', 'ant']));

If you're concerned about the order of properties in the resulting arrays, you can sort them after grouping:

const groupWords = (words) => {
  const groupedObj = words.reduce((a, word) => {
    const key = word[0];
    if (!a[key]) {
      a[key] = [];
    }
    a[key].push(word);
    return a;
  }, {});
  return Object.values(groupedObj)
    .sort((a, b) => a[0][0].localeCompare(b[0][0]));
};

console.log(groupWords(['bear', 'chicken', 'dolphin', 'cat', 'tiger']));
console.log(groupWords(['elephant', 'fish', 'horse', 'bird', 'flamingo', 'dog', 'ant']));

Answer №2

Condensed CertainPerformance's response and converted all text to lowercase initially to ensure sorting accuracy.

function groupStrings(strings) {
    return Object.values(strings.sort().reduce((a, str) => {
        const s = str.toLowerCase();
        const f = s[0];
        a[f] = a[f] ? [...a[f], s] : [s];
        return a;
    }, {}));
}

console.log(groupStrings(['bear', 'chicken', 'dolphin', 'cat', 'tiger']));
console.log(groupStrings(['chevrolet', 'buick', 'dodge', 'bmw', 'mercedes', 'jaguar', 'landrover', 'audi', 'volkswagen', 'cadilac', 'ford', 'toyota', 'tesla']));

Edit

Below are multiple methods utilizing arrays and for loops exclusively. Detailed explanations can be found within the comments:

function groupStrings(strings) {

    // sort the array first
    var sortedStrings = strings.slice().sort();

    // initialize the 2d array with the first word
    var twoDArray = [[sortedStrings[0]]];

    for (var i = 1; i < sortedStrings.length; i++) {

        // obtain the last child array in the 2d array
        var currentArray = twoDArray[twoDArray.length-1];

        // if the initial letter of the current string matches the initial letter of a string in the current child array,
        // append the current string to the current child array
        if (sortedStrings[i][0] === currentArray[0][0]) {
            currentArray.push(sortedStrings[i]);
            currentArray = currentArray.sort();

        // otherwise, create a new child array with the current string
        } else {
            twoDArray.push([sortedStrings[i]])
        }

    }
    
    return twoDArray;
};

console.log(groupStrings(['bear', 'chicken', 'dolphin', 'cat', 'tiger']));
console.log(groupStrings(['chevrolet', 'buick', 'dodge', 'bmw', 'mercedes', 'jaguar', 'landrover', 'audi', 'volkswagen', 'cadilac', 'ford', 'toyota', 'tesla']));

function groupStrings(strings) {

    var alphabet = 'abcdefghijklmnopqrstuvwxyz';
    var twoDArray = [];

    for (var i = 0; i < alphabet.length; i++) {

        // create a temporary array for all words starting with the current letter
        var letterArray = [];

        for (var j = 0; j < strings.length; j++) {

            // if the initial letter of the current string matches the current letter,
            // add it to the letter array
            if (strings[j][0] === alphabet[i]) {
                letterArray.push(strings[j]);
            }
        }

        // if any strings were added, include the letter array in the 2d array
        if (letterArray.length) {
            twoDArray.push(letterArray);
        }
    }

    return twoDArray;
};

console.log(groupStrings(['bear', 'chicken', 'dolphin', 'cat', 'tiger']));
console.log(groupStrings(['chevrolet', 'buick', 'dodge', 'bmw', 'mercedes', 'jaguar', 'landrover', 'audi', 'volkswagen', 'cadilac', 'ford', 'toyota', 'tesla']));

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

Adding the location of the onClick event to the hook - a step-by-step guide

Here is the code I am working with: import { MapContainer, TileLayer } from "react-leaflet"; import React, { useState } from 'react'; export default function App() { const [positionLat, setPositionLat] = useState(null); ...

An automated feature that smoothly transitions a large image onto the screen

I came across a plugin, possibly a slideshow plugin, that smoothly slides a large image along the y-axis. It's hard to explain, but imagine the visible image is only 600px by 300px, while the actual image is 600px by 600px. This plugin would scroll t ...

Include previous input as a "phantom" thumbnail to the slider element of type "range"

https://i.stack.imgur.com/JnuCN.png Using a tutorial from w3schools, I have customized a regular range slider. The objective is to send a new value command to an external MQTT-based home automation system and display the previous value as a ghost-thumb in ...

What could be the issue with my interactive dropdown menu?

I am currently experiencing an issue with a drop down list that is supposed to fetch records from a column in another table, but no records are appearing. Additionally, I would like to add an option in the drop down list labeled "others" for users to inp ...

JavaScript property counterparts

Recently, I've been working on creating alias's for a specific property in my code. var default_commands = {} default_commands['foo'] = "bar"; My goal is to create multiple aliases for the key 'foo' in the object. For examp ...

A comprehensive guide on utilizing the ngFor directive for looping through objects

After trying to iterate over this dataset within my HTML, I attempted a nested ngfor, but unfortunately encountered an error. My attempt involved iterating the object twice with a nested ngfor, resulting in the following error: HabitRecordsComponent.ht ...

How can users change the displayed Twitch channel?

My coding skills aren't the greatest, especially when it comes to something like this. I've tried searching for a solution with no luck, so I apologize if this is too basic or impossible. I have a simple page that loads up Twitch with a predefin ...

Clicking on the user will reveal a modal containing all of the user's detailed information

**I am trying to pass the correct user data to the modal ViewUser component, but it keeps displaying the same user regardless of which user I click on. How can I specify the specific user whose data should be shown? I am sending the user information as a ...

What might be causing the attribute of this Backbone model to be undefined when attempting to access it?

I have a straightforward REST API that provides information about an item at /api/items/:id, which includes the ID and name. I am using a Router to organize my Backbone views. The edit route creates a FormEditItem view, passing the ID from the URL. To ret ...

Initiating a click function for hyperlink navigation

Here is the HTML and JavaScript code that I am currently working with: <!DOCTYPE html> <html> <head> <script src="http://code.jquery.com/jquery-3.3.1.min.js"></script> </head> <body> <a href="#f ...

Using jQuery or Javascript to enclose every character in a given string with an HTML tag

I am trying to create a function that can take a string of text and wrap each letter within that string with an HTML tag such as <i> or <span>. Although I have made some progress, the current solution is not working as expected. The issue I a ...

Modifying the CSS design of specific columns within a table created using JavaScript

A unique way to showcase JSON data in a table is by utilizing a for loop within a function. This method, however, does not assign an ID or Class to the table. To hide the final three columns of this table using CSS, the following code can be employed (whe ...

Is Storybook webpack stuck in a loop, rebuilding and reloading constantly?

While working on a NextJS project with Storybook, I am encountering a recurring issue where the webpack keeps rebuilding continuously without stopping. This relentless rebuilding process puts a strain on my CPU and drains the battery of my device. Even aft ...

Dynamically expanding an array by adding new rows

I am facing a challenge in initializing an empty list and dynamically adding new rows to it during each iteration of a loop. For instance, I start with an empty array as shown below. myarray=[] for i in range(5): calc=[i,i+1,i+4,i+5] After calculati ...

encountering a glitch while using console.log(util.format

Let me start by saying that I am fairly new to working with node.js. A friend of mine assisted me in writing the code snippet below. I have successfully installed the necessary packages search-google-geocode, csv-parser, fs, util, and async using npm. H ...

Incorporate React Pages into Discord Js integration

Chat command "911" generates a bot help list with an embed and three reaction buttons: "forward", "backward", and "delete". The functionality seems fine, but I'm encountering an issue where the reaction buttons only work once. For instance, if I navig ...

Exploring File Reading and 2-Dimensional Array with Array Bound Caution

import java.io.BufferedReader; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStreamReader; public class ReadFromFile { public static void main(String[] args) { String ...

Having Trouble with Your Instafeed Script

I've been working on a project that involves integrating an Instagram feed into a website. However, I'm facing difficulties getting it to function properly. Here's the code that I have implemented. <script type="text/javascript"> ...

Exploring nested list iteration in Python

I have a total of 43 items, each consisting of 75 data points. These 75 points represent different times of the day, and I am looking to calculate the standard deviation of each specific time across all 43 items. I attempted to use a nested for loop, but i ...

store events in a MySQL database using a servlet callback and display them on a full calendar

Hey there! I recently started using the full-calendar jQuery plugin and successfully integrated it into a JSP page. The events on the calendar are loaded from a MySQL database by calling a servlet that generates a JSON array of retrieved elements. Now, I& ...