Categorize the array based on the nested keys

Is there a way in ES6 or Ramda to group an array of objects by an object key and then create a new array of objects based on the grouping? For example, consider the following array of objects:

[
  {
    "name": "ABCD123",
    "code": "GFDGF",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  },
  ...
]

I want to create a new array that's grouped by ptj.desc or ptj.code:

[
  {
    "PTJ": "ABCD 123",
    "data": [
      {
        "name": "ABCD123",
        "code": "GFDGF",
        "ptj": {
          "code": "123",
          "desc": "ABCD 123"
        }
      },
      ...
    ]
  },
  ...
]

I tried using the following code:

const stores = myArray.reduce((r, a) => {
    r[a.ptj.desc] = r[a.ptj.desc] || [];
    r[a.ptj.desc].push(a);
    return r;
}, {});

However, this converts it into an object and I cannot use array.map. Can you advise on how to correct and improve this using ES6 or Ramda? Thank you in advance.

Answer №1

If your goal is to group objects based on the same ptj.desc value and are fine with the resulting object having keys as indexes, you can simply utilize R.groupBy in this manner:

const data = [
  {
    "name": "ABCD123",
    "code": "GFDGF",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  },
  {
    "name": "ANGGUN",
    "code": "DSFD54",
    "ptj": {
      "code": "111",
      "desc": "111 123"
    }
  },
  {
    "name": "GDFDGG",
    "code": "HJ2",
    "ptj": {
      "code": "111",
      "desc": "111 123"
    }
  },
  {
    "name": "POT",
    "code": "POT89",
    "ptj": {
      "code": "222",
      "desc": "222 123"
    }
  },
  {
    "name": "POTER UTAMA",
    "code": "POTER345",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  },
  {
    "name": "ABCD123ABCD",
    "code": "LOLL23",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  },
  {
    "name": "ANGGUN 2",
    "code": "DSFD54",
    "ptj": {
      "code": "111",
      "desc": "111 123"
    }
  },
  {
    "name": "GDFDGG",
    "code": "HJ2",
    "ptj": {
      "code": "111",
      "desc": "111 123"
    }
  },
  {
    "name": "POT",
    "code": "POT89",
    "ptj": {
      "code": "222",
      "desc": "222 123"
    }
  },
  {
    "name": "POTER UTAMA",
    "code": "POTER345",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  }
]

const fn = R.groupBy(R.path(['ptj','desc']))

console.log(fn(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

If your objective is to have a structure similar to the example in your query, then you can combine the above approach with R.map, R.zipObj, and R.toPairs like demonstrated below:

const data = [
  {
    "name": "ABCD123",
    "code": "GFDGF",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  },
  {
    "name": "ANGGUN",
    "code": "DSFD54",
    "ptj": {
      "code": "111",
      "desc": "111 123"
    }
  },
  {
    "name": "GDFDGG",
    "code": "HJ2",
    "ptj": {
      "code": "111",
      "desc": "111 123"
    }
  },
  {
    "name": "POT",
    "code": "POT89",
    "ptj": {
      "code": "222",
      "desc": "222 123"
    }
  },
  {
    "name": "POTER UTAMA",
    "code": "POTER345",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  },
  {
    "name": "ABCD123ABCD",
    "code": "LOLL23",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  },
  {
    "name": "ANGGUN 2",
    "code": "DSFD54",
    "ptj": {
      "code": "111",
      "desc": "111 123"
    }
  },
  {
    "name": "GDFDGG",
    "code": "HJ2",
    "ptj": {
      "code": "111",
      "desc": "111 123"
    }
  },
  {
    "name": "POT",
    "code": "POT89",
    "ptj": {
      "code": "222",
      "desc": "222 123"
    }
  },
  {
    "name": "POTER UTAMA",
    "code": "POTER345",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  }
]

const fn = R.groupBy(R.path(['ptj','desc']))

const fn2 = R.compose(R.map(R.zipObj(['PTJ', 'data'])), R.toPairs, fn)

console.log(fn2(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Answer №2

To group by either ptj.desc or ptj.code, you can utilize the reduce() method. In the following example, we use ptj.desc for grouping.

let proj = [{"name":"ABCD123","code":"GFDGF","ptj":{"code":"123","desc":"ABCD 123"}},{"name":"ANGGUN","code":"DSFD54","ptj":{"code":"111","desc":"111 123"}},{"name":"GDFDGG","code":"HJ2","ptj":{"code":"111","desc":"111 123"}},{"name":"POT","code":"POT89","ptj":{"code":"222","desc":"222 123"}},{"name":"POTER UTAMA","code":"POTER345","ptj":{"code":"123","desc":"ABCD 123"}},{"name":"ABCD123ABCD","code":"LOLL23","ptj":{"code":"123","desc":"ABCD 123"}},{"name":"ANGGUN 2","code":"DSFD54","ptj":{"code":"111","desc":"111 123"}},{"name":"GDFDGG","code":"HJ2","ptj":{"code":"111","desc":"111 123"}},{"name":"POT","code":"POT89","ptj":{"code":"222","desc":"222 123"}},{"name":"POTER UTAMA","code":"POTER345","ptj":{"code":"123","desc":"ABCD 123"}}]

result = proj.reduce(function (a, c) {
  a[c.ptj.desc] = a[c.ptj.desc] || [];
  a[c.ptj.desc].push(c)
  return a;
}, Object.create(null));
console.log(result);

Answer №3

There are multiple approaches to achieve the desired outcome, but the method you've outlined aligns with a key-value lookup using IDs.

First, an array of keys is created (such as {}.ptj.desc), then all objects are mapped to a new object where the keys match the previously defined array. The result? Success.

Check out the example provided below. Hopefully, it meets your requirements.

var mainStore = [
  {
    "name": "ABCD123",
    "code": "GFDGF",
    "ptj": {
      "code": "123",
      "desc": "ABCD 123"
    }
  },
  // Other objects omitted for brevity
];

var idList = mainStore.map(item => item.ptj.desc);

var dataMap = mainStore.reduce(( dataMap, item ) => {
  dataMap[ item.ptj.desc ] = item;
  return dataMap;
}, {});

// Proceed with operations based on idList 

var onlyCodes = idList.map(id => dataMap[ id ].ptj.code);
var onlyNames = idList.map(id => dataMap[ id ].name);

console.log(onlyCodes);
console.log(onlyNames);

Answer №4

If utilizing a map function is your goal, consider implementing it in the following manner:

const newArray = Object.keys(locations).map(index => locations[index])

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

Reorganizing a list in AngularJS after adding a new item

I have made edits to the AngularJS ordering example in my Plunker. The ordering works fine initially, but when I add a new person using code to periodically update the list of contacts, the new person gets added to the bottom without re-sorting. Is there a ...

Setting the percentage height of parent and child divs in a precise manner

Trying to work through this without causing chaos. I have a container div containing three floated left child divs, with the container div set to 100% height like so: .Container { height: 100%; min-width: 600px; overflow-y: hidden; } One of the child divs ...

Show a loading progress image during the page loading process (not during form submission)

Is there a way to show a loading GIF image while a page is loading or during postbacks using jQuery and JavaScript for long running tasks or processes that take a significant amount of time to execute? I attempted a solution but the loading image is not d ...

A guide on truncating a portion of a string within a PHP two-dimensional array

Given an array named $arr, the task is to trim each element from ['name'] to a specified length and then append additional characters. I successfully achieved this with a regular array, but encountered difficulties when working with a two-dimensi ...

In React, the state's value will revert back to its initialState whenever a new value is assigned

My App component has a simple functionality where it controls the state of a value to display a header. By using an onClick function, I'm updating the isHeaderVisible value to True in the Home component when a logo is clicked and another route is take ...

Having trouble locating the objects in the parent scope of an Angular directive

My custom directive needs to access the object $scope.$parent.users. When I use console.log $scope.$parent: myDirective.directive('scheduleItem', function(){ return { restrict: 'EA', link: function($sco ...

Executing numerous Ajax requests within a single Rails view

Two ajax requests are being used on a single page, one showcasing a date and the other displaying a calendar. The first request updates the date upon clicking a date on the calendar. The second request allows for switching between months on the calendar. ...

Utilizing Mongoose Schema Enums Alongside TypeScript Enums

In our Typescript-based NodeJs project utilizing Mongoose, we are seeking the right approach to define an enum field on a Mongoose schema that aligns with a Typescript enum. To illustrate, consider the following enum: enum StatusType { Approved = 1, ...

The act of scrolling through list elements does not initiate upon the first click

I'm trying to create a script that allows users to scroll through list elements by clicking on "previous" and "next" links. However, I'm running into an issue where when the user clicks on the "next" button for the first time, they have to click ...

Passing a DOM element from Selenium to JQuery and retrieving the results in C#

I recently encountered some challenges with using JQuery to search for information and send it back to Selenium C# in my project. After some trial and error, I was able to figure it out and wanted to share my findings. Specifically, I focused on: How ca ...

Authentication Error (401) in WordPress JWT

Recently, I came across WordPress and started using it. However, I encountered some issues while trying to integrate JWT with a custom endpoint. Despite configuring my API and JWT correctly, I faced an authentication problem during my AJAX request. It&ap ...

ImageMapster for perfect alignment

I'm struggling with centering a div that contains an image using imagemapster. When I remove the JS code, the div centers perfectly fine, indicating that the issue lies with the image mapster implementation. It's a simple setup: <div class=" ...

The table's content extends beyond the confines of the page

I have an HTML page where I am embedding an SSRS report. The report extends beyond the page as shown in the image below: This is the table that is generated: <table cellpadding="0" cellspacing="0" id="ctl00_MainContent_FiveYearReportViewer_fixedTable" ...

Place the child's text within the matching parent data element

I'm having trouble assigning the text values of children to their respective parent's data element, as all the values are being combined. Here is my code: HTML <ul> <li class="item" data-v="1"> <div class="xyz" data-v="2"> ...

Operating on JSON objects/arrays according to their values

I am working on developing a function that accepts a string as its first argument and a JSON LIST as its second argument: [ { "date": "09/09/18", "how_many": 11, "species": "XXXXX" }, { "date": "04/11/17", ...

Exploring the functionalities of the useState object with mapping techniques

While attempting to convert my class-based component to a functional style, I encountered the following code: const [foo, setFoo] = useState(null); const [roomList, setRoomList] = useState([]); useEffect(() => { setRoomList(props.onFetchRooms(props.to ...

Issues related to ng-model within a dropdown list

Currently, I am facing an issue with retrieving the selected value from a select element using ng-model. Even though the value is displayed correctly on the application page, it remains at the initial value in the app controller. Despite my efforts to find ...

A JavaScript regular expression for identifying IMDB URLs

Could someone please help me identify the issue with this JavaScript code? "http://www.imdb.com/title/tt2618986/".match("~http://(?:.*\.|.*)imdb.com/(?:t|T)itle(?:\?|/)(..\d+)~i"); I tested it here https://regex101.com/r/yT7bG4/1 and it wo ...

Issue with Zebra_Calendar and JSON compatibility in Internet Explorer 7

I have integrated the Zebra_Calendar jQuery plugin on my website, but encountered an issue when including a JSON implementation. Specifically, I am facing an "Object Doesn't Support This Property or Method" error related to string.split during initial ...

Using event.target.value in find() caused the function to return undefined, but it worked as expected when storing the value in

I am facing a peculiar issue. I am working with a select component that passes a value called "classID" up to a useState. There is an array mapped over the select component which is sent from a NodeJS API and looks like this: [{classID: 371, teacherID: 1, ...