Ways to convert an array containing objects in JavaScript

I'm struggling to transform an array into another array and keep running into errors. Specifically, I can't figure out how to push into found[0].children. It feels like my current approach is messy and incorrect. Can someone provide guidance on how to tackle this issue more effectively?

My goal is to convert the following input array:

const data =
[
    {value: "29-08-2020 16:00", visible: 0},
    {value: "29-08-2020 16:30", visible: 1},
    {value: "29-08-2020 17:00", visible: 0},
    {value: "30-08-2020 15:00", visible: 1},
    {value: "30-08-2020 15:30", visible: 1}
];

Into the desired output array structure:

const result =
[
    {
        id: '29/08/2020',
        label: '29/08/2020',
        children:
        [
            {
                id: '16:00',
                label: '16:00',
                isDisabled: true
            },
            {
                id: '16:30',
                label: '16:30'
            },
            {
                id: '17:00',
                label: '17:00',
                isDisabled: true
            }
        ],
    },
    {
        id: '30/08/2020',
        label: '30/08/2020',
        children:
        [
            {
                id: '15:00',
                label: '15:00'
            },
            {
                id: '15:30',
                label: '15:30'
            }
        ]
    }
];

I've attempted a solution using the following function, but I'm not satisfied with it as it doesn't feel like the best way to approach the problem:

function convertDates(inputData) {
    var outputData = [];
    inputData.forEach(element => {
        var splitValues = element.value.split(' ');
        var date = splitValues[0];
        var time = splitValues[1];
        var foundEntry = outputData.filter(entry => entry.id == date);
        if (foundEntry.length > 0) {
            foundEntry[0].children.push({
                'id': time,
                'label': time,
                disabled: element.visible == 0
            });
        } else {
            outputData.push({
                'id': date,
                'label': date,
                'children': {'id': time, 'label': time, disabled: element.visible == 0}
            });
        }
    });
    return outputData;
}

Answer №1

To optimize performance, you can condense the array and then loop through the resulting set for a particular group.

const
    data = [{ value: "29-08-2020 16:00", visible: 0 }, { value: "29-08-2020 16:30", visible: 1 }, { value: "29-08-2020 17:00", visible: 0 }, { value: "30-08-2020 15:00", visible: 1 }, { value: "30-08-2020 15:30", visible: 1 }],
    result = data.reduce((r, { value, visible }) => {
        let [date, time] = value.split(' '),
            temp = r.find(q => q.id === date);
       
        if (!temp) r.push(temp = { id: date, label: date, children: [] });
        temp.children.push({ id: time, label: time, ...(!visible && { isDisabled: !visible }) });
        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answer №2

Your suggestion is on point! Utilizing a map for the simplicity of lookup and generating an empty entry with an empty children array when it's not found is a great approach:

function dateoptions (datelist) {
  const dateObjects = new Map()

  for (const { value, visible } of datelist) {
    const [date, time] = value.split(' ')

    if (!dateObjects.has(date)) {
      dateObjects.set(date, {
        id: date,
        label: date,
        children: []
      })
    }

    dateObjects.get(date).children.push({
      id: time,
      label: time,
      ...!visible ? { isDisabled: true } : {}
    })
  }

  return Array.from(dateObjects.values())
}

1: Why opt for a map over an object? The reason is that the iteration order of object values is not defined, although most modern browsers currently maintain insertion order. With a map, the order is guaranteed.

Answer №3

Even Internet Explorer 6 is compatible with the solution provided below.

var data =
[
    {value: "29-08-2020 16:00", visible: 0},
    {value: "29-08-2020 16:30", visible: 1},
    {value: "29-08-2020 17:00", visible: 0},
    {value: "30-08-2020 15:00", visible: 1},
    {value: "30-08-2020 15:30", visible: 1}
];

function convertDate(datelist)
{
    var result = [],
        dateObjects = {},
        i;

    for(i in datelist)
    {
        var item = datelist[i],
            arr = item.value.split(' '),
            date = arr[0].split('-').join('/'),
            childItem = {id: arr[1], label: arr[1]};

        if(!dateObjects[date])
            dateObjects[date] = {id: date, label: date, children: []};

        if(!item.visible)
            childItem.isDisabled = !0;

        dateObjects[date].children.push(childItem);
    }

    for(i in dateObjects)
        result.push(dateObjects[i]);

    return result;
}

//The use of JSON.stringify was introduced in Internet Explorer version 8
console.log(JSON.stringify(convertDate(data), 0, '\t'));

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

Enhancing Custom Elements in JointJS with a Port

I followed the steps from the jointjs tutorial to create a custom element, which looks like this: CustomRect = joint.dia.Element.define('example.CustomRect', { attrs: { rect: { refX: 0, refY: 0, refWidth: '116', ...

The v-autocomplete feature in vuetify doesn't allow for editing the text input after an option has been selected

Link to code on CodePen: CodePen Link When you visit the provided page and enter "joe" into the search box, choose one of the two Joes that appear. Try to then select text in the search box or use backspace to delete only the last character. You will no ...

"Enscroll – revolutionizing the way we scroll in

I recently incorporated the "enscroll" javascript scroll bar into my webpage. You can find more information about it at <div id="enscroll_name"> <ul> <li id="p1">product1</li> <li id="p2">product2</li> ...

Why isn't ng-show functioning properly with the returned value of a function?

Here's a simple logic: Display the link only when at least one checkbox is checked. This functionality is implemented within the calculate checkbox function. JavaScript $scope.calculateChecked = function() { var count = 0; angular.forE ...

Seeking assistance in identifying the highest value in JavaScript (excluding the use of the max method)

Greetings and thank you for stopping by. I'm new to Javascript and currently facing an issue that I could use some help with. I am trying to identify the highest number from a set of variables using conditional statements within a function, but I seem ...

Strangely peculiar glitch found in browsers built on the Chromium platform

During a school assignment, I'm attempting to adjust the width of a button using Javascript. Below is my code: const button = document.querySelector("button"); button.addEventListener("click", () => { console.log(button.offsetWidth); butto ...

Alternatives to using $.getJSON()

When utilizing jQuery within the React/Redux environment, what alternative library is typically used for handling straightforward REST calls instead of $.getJSON or $.postJSON? Is there a widely-used option that functions similarly to node's http mod ...

When making an AJAX request in a jQuery Autocomplete Textbox using .NET MVC, the term is found to be

Question: <script type="text/javascript"> $(document).ready(function () { $("#OriginInput").autocomplete({ source: function (request, response) { $.ajax({ url: '@Url.Action("AjaxMethod","MyUrl")&a ...

Submit files via AJAX with an upload form

I'm facing an issue with uploading a file and saving it on a server using jQuery AJAX. I attempted the process but encountered some difficulties. The file doesn't seem to be processed correctly. Here's what I've been doing: HTML Code ...

How is it that functions are perceived as objects?

Currently, I am delving into the realm of JS/ES and find myself puzzled by classes and objects. The two blocks of code displayed below achieve the same outcome; however, the latter unmistakably employs a class. But what exactly is the former using? Wasn&a ...

As the cursor moves, the image follows along and rotates in sync with its

Can anyone help me figure out how to create a moving image that follows the mouse cursor? I have a radial pie menu with an image in the middle, and I want it to spin and rotate as the mouse moves. Any ideas on how I can achieve this effect? I would greatl ...

Struggling to Confirm Inaccuracies in Material UI Forms

Struggling to validate form errors in React with Material UI using JOI and running into issues. Even the console.log() results are not showing up in my validate function. The error display is also confusing. ... import React from "react"; import ...

How can I calculate the total sum of values in an array retrieved from an API call?

Within the array this.state.companiesIncome, I've got 50 objects each containing a {value and date}. However, when attempting to retrieve this.state.companiesIncome[2].value, I'm encountering an error stating: TypeError: Cannot read property &apo ...

The API is providing data, but it's being returned within an ambiguous object. What could be causing this confusion?

Utilizing https and async for simultaneous calls to retrieve two objects, then storing them in an array. The call is structured as follows: if (req.user.isPremium == false) { // Free user - Single report let website = req.body.website0; let builtWit ...

Apply a border to the navbar when it hovers over a selected element

export const NavBar = () => { return <div className="navbar">this is navbar</div>; }; const Content = () => { return ( <div className="main"> <div className="background"> some content </div> ...

Allowing users to submit content in a textarea field by pressing the enter key in

<td> <textarea name="message" id="message" rows="1" style="padding: 10px;margin-left: 12px;border-radius: 10px; margin-right: 0px; width: 430px;"></textarea> <td style="padding-left:0px"> <a title="Send" id="sendB ...

Switching between boolean values based on another value in react is a common practice

When a user is chosen from the list, a boolean value becomes true. If the chosen user is then unselected, the boolean turns false. This boolean will stay true if another user is selected from the list. Here's the code snippet: import React, { useEffec ...

Combining Gridstack.js with Vue 3 components

I'm currently working on setting up a gridstack.js dashboard using Vue 3 and I am looking to have the grid stack items incorporate dynamic vue 3 components. The issue arises where these grid stack items can only accept HTML content. Even though the d ...

Address the scenario where only one of the two AJAX requests was able to successfully complete

I have a scenario where I am making two ajax requests using jQuery deferred objects. I have successfully handled the case when both requests are executed successfully. Now, I need to handle the situation when one request is successful and the other fails. ...

Want to achieve success with your AJAX calls in JavaScript? Consider using $.get

As I clean up my JavaScript code, I am looking to switch from using $.ajax to $.get with a success function. function getresults(){ var reqid = getUrlVars()["id"]; console.log(reqid); $.ajax({ type: "POST", url: "/api/ser/id/", ...