Arrange objects array by quarterly-yearly data in JavaScript

My data set consists of objects as shown below:

[  
   {  
      "name":"Q1'2016",
      "y":0
   },
   {  
      "name":"Q2'2016",
      "y":0
   },
   {  
      "name":"Q3'2016",
      "y":0
   },
   {  
      "name":"Q4'2015",
      "y":0
   }
]

I need to arrange these objects in quarterly order, starting with Q4'2015, followed by Q1'2016, and so on.

Is there a way to accomplish this sorting?

Answer №1

If you want to organize your object based on quarter-year information, you can utilize the sort method with a callback function. By mapping the quarters to month values, you can convert them into year/month dates for comparison purposes when sorting the data. Here's an example:

var data = [{
  "name": "Q1'2016",
  "y": 0
}, {
  "name": "Q2'2016",
  "y": 0
}, {
  "name": "Q3'2016",
  "y": 0
}, {
  "name": "Q4'2015",
  "y": 0
}];

var quarterToMonthMap = {
  "Q1": 0,
  "Q2": 3,
  "Q3": 6,
  "Q4": 9
}

function sortByQuarterYear(lhs, rhs) {
  var lhsQuarterYear = lhs.name.split("'");
  var rhsQuarterYear = rhs.name.split("'");
  var lhsDate = new Date(lhsQuarterYear[1], quarterToMonthMap[lhsQuarterYear[0]]);
  var rhsDate = new Date(rhsQuarterYear[1], quarterToMonthMap[rhsQuarterYear[0]]);
  return lhsDate.getTime() - rhsDate.getTime();
}

document.write(JSON.stringify(data.sort(sortByQuarterYear)));

Answer №2

If you want to sort by year and quarter, you can achieve this using the following ES6 snippet. (It's also possible with ES5, but I prefer ES6)

input.map((obj, index) => obj.name.split("'").reverse().concat(index)).sort().map(arr => input[arr[2]]);

Let's break this down for better understanding

input.map((obj, index) => obj.name.split("'").reverse().concat(index))

The map() function creates a new array by calling a given function on each element in the original array.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

In our case, we split the "name" property of each object by the character "'", reverse the resulting array, and add the current index to it.

This operation results in an array like:

[
    ["2016", "Q1", 0], 
    ["2016", "Q2", 1], 
    ["2016", "Q3", 2], 
    ["2015", "Q4", 3]
]

We then use .sort,

The sort() method arranges the elements of an array and returns it. The default sorting order is based on Unicode points.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

After sorting, the array looks like:

[
    ["2015", "Q4", 3], 
    ["2016", "Q1", 0], 
    ["2016", "Q2", 1], 
    ["2016", "Q3", 2]
]

Now, although the indexes are not ordered within, we can utilize this to establish order.

By another application of map, we retrieve the original object related to the stored index in our temporary arrays.

.map(arr => input[arr[2]]);

Upon executing this sequence, the resultant array will be structured as follows:

[
    {
        name: "Q4'2015",
        y: 0
    }, {
        name: "Q1'2016",
        y: 0
    }, {
        name: "Q2'2016",
        y: 0
    }, {
        name: "Q3'2016",
        y: 0
    }
]

Give it a try with the provided demo:

let input = [  
   {  
      "name":"Q1'2016",
      "y":0
   },
   {  
      "name":"Q2'2016",
      "y":0
   },
   {  
      "name":"Q3'2016",
      "y":0
   },
   {  
      "name":"Q4'2015",
      "y":0
   }
];
    
input = input.map((obj, index) => obj.name.split("'").reverse().concat(index)).sort().map(arr => input[arr[2]]);

console.log(input);

To replicate this process using ES5:

input.map(function(obj, index){
    return obj.name.split("'").reverse().concat(index);
}).sort().map(function(arr){
    return input[arr[2]];
});

Answer №3

By utilizing the .sort() method alongside a comparator function, it becomes possible to easily transform values like "Q1'2016" into "2016Q1". This transformation allows for straightforward alphanumeric comparisons such as "2016Q1" > "2015Q4".

function sortQuarters(arr) {
  function reformat(v) {
    return v.replace(/(Q\d)'(\d{4})/, "$2$1");
  }
  return arr.sort(function(a, b) {
    return reformat(a.name).localeCompare(reformat(b.name));
  });
}

console.log(sortQuarters([  
   { "name":"Q1'2016", "y":0 },
   { "name":"Q3'2016", "y":0 },
   { "name":"Q2'2016", "y":0 },
   { "name":"Q4'2015", "y":0 }
]));

(It is important to note that this reformatting only occurs within temporary variables during sorting and does not alter the original values in the array. Additionally, the provided function changes the order of the passed array but returns the same array rather than creating a new one.)

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

Displaying a pop-up message over the "Login button" for users who are not currently logged in

I am currently in the process of developing a website using node.js and express. I have successfully integrated all the login functionality through passport, allowing users to easily log in or out by utilizing res.user. However, I now want to enhance the ...

Problem with the property `className` not adding correctly on `$scope.eventSource`

Currently, I am utilizing the AngularJS directive to integrate the Arshaw FullCalendar. However, I am encountering an issue where the className specified in $scope.eventSource is not appearing on the event object. Here is a snippet of my code: $scope.even ...

Can Vue.js support two-way data-binding without the use of an input element?

Here is the code snippet that I'm working with: <div id="app"> {{ message }} </div> JavaScript: myObject = {message:"hello"} new Vue({ el: '#app', data: myObject }) When I update myObject.message, the content within th ...

Challenges with loading elements in Protractor

I'm feeling a bit confused about Protractor at the moment. It seems like sometimes my elements load in time for the next action to happen, while other times they do not. I'm assuming this has something to do with its asynchronous nature. For ex ...

Retrieving the name of the final object in a ListView

While working on parsing this JSON data: { "technology" : [ { "title" : "Android", "images" : [ { "name" : "Android - I" }, { "name" : "Android - II" }, { "name" : "Android - III" } ] } ] } I have successfully parsed the technology and images JSON Arra ...

Remove outdated cards from a React array

I am facing a complicated situation and require some assistance. Below is the code snippet: The function provided below is used to determine if a credit card has expired or not. It returns true if the card is expired and false if it's valid. const i ...

JavaScript Button Selector & Name Generator

I'm currently working on a Java project to develop a name generator. I have successfully implemented basic functionality using tables. However, I am now looking to enhance this by allowing the script to seamlessly switch between tables using radio but ...

The optimal and most secure location for storing and retrieving user access credentials

After receiving a list of locations accessible to the session user from the server, I am seeking the ideal location to store these roles in Angular. This will allow me to determine whether or not to display specific routes or buttons for the user. Where ...

How to efficiently organize MongoDB data in Spring Boot applications using MongoTemplate

My Objective I am aiming to translate the following query into Spring Boot using MongoTemplate: db.getCollection("employees").find().sort({ hire_date: 1 }).limit(10) My Investigation I have come across several resources discussing sorting me ...

Separating the web address path and extracting just two segments

How do I extract specific parts of a user-entered path in JavaScript? For example, if the user enters the following path: /content/mypath/myfolder/about/images/April/abc.jpg I only want to grab: April/abc.jpg $(document).ready(function(){ $(' ...

To what extent can the Vuetify data tables be customized?

https://i.sstatic.net/x4qhA.png I am currently working on replicating the layout shown in the image above. The table is already functional in my Vue project. The following code snippet represents the Vuetify datatable template in use: <v-card> ...

utilize the functionality of chartjs to overlay images on top of pie chart segments

Currently working with chartjs version 3.6.0 and vue version 2.6.11. My goal is to create charts using chartjs in combination with vue, which has been going smoothly overall. However, I have encountered a challenge that I am struggling to solve. Specifical ...

A guide on implementing AJAX redirection in MVC

I currently have a button that, when clicked, takes input values and redirects to another page in JavaScript using the following code window.location = "Action Param1=value1&Param2=Value2". However, I am looking to avoid using query strings for this me ...

Dealing with the issue of asynchronous operations in a controller using async/await function

Something strange is happening here, even though I'm using async await: const Employee = require('../models/employee'); const employeeCtrl = {}; employeeCtrl.getEmployees = async (req, res) => { const employees = await Employee.find( ...

What is the method to have the text cursor within a text field start a few pixels in?

I need a text field with the cursor starting a few pixels (let's say 4) from the left-hand side. I am aware that this can be achieved by adjusting the size of the text field using padding, but I am curious if there is a way to resize the text box with ...

Learn the steps to transform a 2D array into a value object using Ruby

Consider the following 2D array: a = [["john doe", "01/03/2017", "01/04/2017", "event"], ["jane doe", "01/05/2017", "01/06/2017", "event"]...] I am interested in converting it into a value object in ruby. While I found a solution for hash arrays here, I ...

methods for detaching event listener from bootstrap carousel indicator elements

I am currently utilizing the bootstrap5 carousel feature and I am seeking a way to trigger a custom event when either the previous or next indicators are clicked. My goal is to stop the default bootstrap event from being triggered, however my attempts at v ...

Arrange the data by a derived column while looping

I'm looking for assistance in sorting this table by the calculated $changepercentage. The table contains over 1000 records uploaded in date order. I've attempted to use arsort() and SORT() functions, but PHP is indicating that it's not an ar ...

Three.js: How to Make a Camera Circle a Sphere?

How can we use Three.js and JavaScript/ WebGL to create a camera that orbits a sphere at a fixed height, with a fixed forward speed, and maintaining a fixed orientation in relation to the sphere? The user should only be able to steer the camera left and ri ...

Vue: Opening all GmapInfoWindows simultaneously upon clicking one

I am working on a platform where users can report crimes or incidents by placing markers on a map. These markers with all the reported incidents are then displayed on another map. Each marker has an info window that provides details about the incident and ...