Combining JSON array objects in Vanilla Javascript to create a nested array based on a shared value

I have been searching for a solution to address my specific issue but have not found an exact match. If there is a similar question, please provide a link to the solution.

I am looking to merge an array of objects that share a common value using vanilla Javascript. I have a JSON file that will generate the following javascript object, and I am unable to alter the original structure. Each object will have different nested names and values, but the common value is found in name[0].

var data = [
  {
    name: [
      'Data 1', // common value
      '1 Jan, 2019', // same value, should not be overwritten/merged
      'hotfix dec'
    ],
    value: [
      'hotfix1.fsfix',
      'hotfix1.txt'
    ]
  },
  {
    name: [
      'Data 1', // common value
      '1 Jan, 2019' // same value, should not be overwritten/merged
    ],
    value: 'data1.jar'
  },
  {
    name: [
      'Data 2',
      '1 Feb, 2019'
    ],
    value: 'data2.fsfix'
  },
  {
    name: [
      'Data 2',
      '1 Feb, 2019'
    ],
    value: 'data2.jar'
  },
  {
    name: [
      'Data 3',
      '1 Mar, 2018'
    ],
    value: 'data3.fsfix'
  }
]

The desired output is to merge nested objects that share the same name[0].

var data = [
  {
    name: [
      'Data 1', // common value
      '1 Jan, 2019', // same value, should not be overwritten/merged
      'hotfix dec'
    ],
    value: [
      'data1.fsfix',
      'data1.txt',
      'data1.jar' // Added after the merge
    ]
  },
  {
    name: [
      'Data 2',
      '1 Feb, 2019'
    ],
    value: [
      'data2.fsfix',
      'data2.jar' // Added after the merge
    ]
  },
  {
    name: [
      'Data 3',
      '1 Mar, 2018'
    ],
    value: 'data3.fsfix'
  }
]

With this new merged structure, I plan to create a function to iterate through each array set. Thank you in advance for your help.

Answer №1

To organize the data based on the first name entry, one can utilize a Map. The data can then be filled into the value property within the respective Map value. Additionally, any extra values in the name arrays (beyond the first two entries) can be gathered, followed by the extraction of the Map values.

This approach maintains a linear time complexity:

var data = [{name: ['Data 1', '1 Jan, 2019', 'hotfix dec'],value: ['hotfix1.fsfix','hotfix1.txt']},{name: ['Data 1', '1 Jan, 2019'],value: 'data1.jar'},{name: ['Data 2','1 Feb, 2019'],value: 'data2.fsfix'},{name: ['Data 2','1 Feb, 2019'],value: 'data2.jar'},{name: ['Data 3','1 Mar, 2018'],value: 'data3.fsfix'}];

const map = new Map(data.map(o => 
    [o.name[0], { name: o.name.slice(0,2), value: [] }]));
data.forEach(o => map.get(o.name[0]).value.push(...[].concat(o.value)));
data.forEach(o => map.get(o.name[0]).name.push(...o.name.slice(2)));
const result = Array.from(map.values(), o => o.value.length === 1 
    ? { ...o, value: o.value[0] } : o);

console.log(result);

The map-function passed to the Array.from method serves as a callback function. Its purpose is to transform value arrays with only one string into that single string. If this transformation is unnecessary, the callback can be omitted and simply call Array.from(map.values()).

Answer №2

There are some Array methods that could potentially help achieve the desired outcome (code snippet provided below, though it has not been tested):

// Utilizing Array methods to merge matching entries by pushing values from matching objects to each other
data = data.map(entry => {
    let matchingObjects = data.filter(match => {
        return match.name[0] === entry.name[0];
    });
    matchingObjects.forEach(match => {
        if (match !== entry) {
            var flatValue = [entry.value].flat();
            entry.value = flatValue.push.apply(flatValue, [match.value].flat());
        }
    });
});

// Removing duplicates by filtering out all but the first entry of each name[0]
data = data.filter((entry, index) => {
    return index === data.findIndex(match => {
        return match.name[0] === entry.name[0];
    });
});

Answer №3

You have the option to utilize a combination of reduce and map to achieve your desired result. This dynamic duo offers great power and versatility.

    const information = [{name: ['Data 1', '1 Jan, 2019', 'hotfix dec'],value: ['hotfix1.fsfix','hotfix1.txt']},{name: ['Data 1', '1 Jan, 2019'],value: 'data1.jar'},{name: ['Data 2','1 Feb, 2019'],value: 'data2.fsfix'},{name: ['Data 2','1 Feb, 2019'],value: 'data2.jar'},{name: ['Data 3','1 Mar, 2018'],value: 'data3.fsfix'}];

    const mappedData = information.reduce((accumulator, current)=>{
        identifier = current.name[0];
        accumulator[identifier] = accumulator[identifier] || {
            name: [],
            value: []
        };
        const dataValue = Array.isArray(current.value) ? current.value : [current.value]

        accumulator[identifier].name = [...accumulator[identifier].name, ...current.name.filter((item)=>accumulator[identifier].name.indexOf(item)===-1)]
        accumulator[identifier].value = [...accumulator[identifier].value, ...dataValue.filter((item)=>accumulator[identifier].value.indexOf(item)===-1)]

        return accumulator
    },{})
    const finalResult = Object.keys(mappedData).map(key=> {
        const info = mappedData[key];
        info.value = info.value.length===1 ? info.value[0] : info.value
        return info;
    })

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

Is it feasible to cancel or clear the queue for a jQuery fadeOut function after a delay is specified? If so,

Can anyone help me out with this question? Is there a way to eliminate the delay in chaining? Mn.Base.TopBox.show = function(timedur){ $('#element').fadeIn().delay(timedur).fadeOut(); } Mn.Base.TopBox.cancelFadeout = function(){ } I&apos ...

Setting input field value using jQuery depending on the attribute value

Here is an example of an input field: <input data-checkout="card-number" type="tel" placeholder="card number" autocomplete="off" class="input-control" value=""> I am looking to use jQuery to set a value in this field. How can I retrieve the attribu ...

The function is receiving an empty array of objects

This code is for an Ionic app written in typescript: let fileNames: any[] = []; fileNames = this.getFileNames("wildlife"); console.log("file names:", fileNames); this.displayFiles(fileNames); The output shows a strange result, as even though there ar ...

Access licensedContent property on YouTube API using PHP

Trying to improve the consistency of music search results on the Youtube API, I decided to categorize content into licensed and non-licensed. Here is the Json response from the API call: { "kind": "youtube#videoListResponse", "etag": "\"XI7nbFXulY ...

The Firebase signInWithPopup functionality suddenly shuts down in a Next.js project

Incorporating the signInWithPopup function for signing in has been successful during the development stage on my local server. const firebaseAuth = getAuth(app); const provider = new GoogleAuthProvider(); const [{ user, cartShow, cartItems }, dispatc ...

Jackson: decoding nested arrays

Trying to make sense of this nightmare JSON... [ ["X", "Y", 0.00010919, 0, null, null, null], ["X", "Y", 0.00210919, 0, null, null, null], ["A", "B", 0.00310919, 0, null, null, null] ] I'm having trouble getting Jackson to properly parse it and m ...

Problem with JSON in Spring Boot REST API

Within my spring boot rest application, there is a controller containing the method below. This method utilizes hibernate to retrieve data from an Oracle DB. The problem arises when I call this service, as it returns a HTTP ERROR 500. Strangely, no error ...

Transform a graphviz.dot.Digraph object into a networkx.Graph

Question Is there a way to transform a graphviz.dot.Digraph into a networkx.Graph or any of its subclasses? Motivation I am working with LightGBM, a tree-based algorithm implementation that generates a graphviz.dot.Digraph object. While this object can ...

Updating Tailwind CSS to accommodate older web browsers by converting modern rgba() notation to be browser-compatible

I am facing a challenge with Tailwind CSS v3+ as it builds colors into the rgb space/color notation that is not compatible with an older browser (Safari 11) that my web app now needs to support. For example, rgb(163 160 158 / var(--tw-bg-opacity) The iss ...

Autocomplete feature seems to be functioning properly in the online demonstration, while it does not seem

I can see that the autocomplete feature is working in the example provided, but it's not functioning properly in my attempt. What could be causing this issue? <!doctype html> <html lang="en"> <head> <meta charset="utf-8> & ...

Using JSON and Jquery in Struts2 action

I am looking to transfer my JSON object from JavaScript to a Struts2 Action. Here is a sample JSON Object: { "lists":["list1","list2","list3","list4","list5"], "maps": { "key4":"value4","key3":"value3","key5":"value5","key ...

Retrieving two sets of AJAX data at the same time

Recently, I've encountered a challenge with filling in data from a MySQL server via PHP into two tables in my HTML. As someone new to website development, I might not be articulating the issue correctly. In my HTML, I've included my external .js ...

Ldap.js: exploring nested searches

My current task involves using ldapjs to conduct a search where the filter is dependent on the outcome of a preceding search. ldapClient.search(base1, opts1, (err1, res1) => { res1.on("searchEntry", entry => { const myObj = { attr1: entr ...

Assign a value to an object within a Vue data property

Hey there, I am currently learning vuejs and facing an issue with setting an object value to a vue data property. data: () => ({ newTodo: "", todoObj: { title: newTodo, undo: false }, toDoList: [ { title: "Study", undo: false }, ...

Controlling international shortcuts for numerous npm packages

Within my root folder, I have 3 npm projects organized in a more complex structure than the following example (using webpack, JS frameworks, etc.), but for simplicity sake, here is the layout: root ├── root_index.js ├── package.json ├── p ...

What is the best way to access a Node/Express API key from the .env file in front-end JavaScript code?

Currently, I am utilizing an OpenWeatherMap API key within my client-side JavaScript for a basic weather application built using Node and Express. However, I understand that this approach is not secure for production environments, so I have installed doten ...

Avoiding the capturing of events on $( document ).mousemove

Each time the browser detects a $( document ).mousemove event, my function is invoked. The performance is smooth with an empty page, but once I introduce a div element and hover over it, the function gets executed twice: first on the document and then agai ...

Is there a way to use node.js to retrieve a video in mp4 format?

My goal is to allow users to download a video from my AWS S3 bucket in MP4 format: app.get("/download_video", function(req,res) { filename = "s3.xxx.amazon.com/bucketname/folder/video_example.mp4"; // I'm unsure about the next steps }); Whil ...

The JQuery TextNTags plugin eliminates tag formatting once the trigger syntax has been modified

I have incorporated the JQuery TextNTags plugin into my web application. Here is the original code snippet: $.browser = { webkit: true }; $(function () { $('textarea.tagged_text').textntags({ triggers: {'!': { ...

(React) Error: Unable to access property 'this' as it is set to undefined while trying to utilize refs

When using a ref in React to refer to an input field, I encountered an error: "Uncaught TypeError: Cannot read property 'this' of undefined". Despite having defined the ref, React seems unable to locate it in my code. What could be causing this i ...