Organize the array based on the grandchild's value

Consider this scenario: I have a collection of objects, where each object contains another collection of objects. The structure is as follows:

[
    {
        "dislikes": [
            {
                "createDate": {
                    "date": 11,
                    "day": 0,
                    "hours": 18,
                    "minutes": 15,
                    "month": 10,
                    "seconds": 11,
                    "time": 1541956511001,
                    "timezoneOffset": -60,
                    "year": 118
                },
            },
            {
                "createDate": {
                    "date": 11,
                    "day": 0,
                    "hours": 18,
                    "minutes": 15,
                    "month": 10,
                    "seconds": 11,
                    "time": 1541956511008,
                    "timezoneOffset": -60,
                    "year": 118
                },
            }
        ],
    },
    {
        "dislikes": [
            {
                "createDate": {
                    "date": 11,
                    "day": 0,
                    "hours": 18,
                    "minutes": 15,
                    "month": 10,
                    "seconds": 11,
                    "time": 1541956511011,
                    "timezoneOffset": -60,
                    "year": 118
                },
            },
            {
                "createDate": {
                    "date": 11,
                    "day": 0,
                    "hours": 18,
                    "minutes": 15,
                    "month": 10,
                    "seconds": 11,
                    "time": 1541956511028,
                    "timezoneOffset": -60,
                    "year": 118
                },
            }
        ],
    }
]

I am looking to organize the users and their dislikes based on the time in the dislikes. Essentially, the user with the earliest dislike should appear first, along with the earliest dislike within each user's dislikes array. It seems like multiple sorting operations are needed, but what would be the best approach for achieving this?

Answer №1

To organize the items based on their earliest dislike, one approach is to map each item and include a property that holds the timestamp of the oldest dislike. Then, the items can be sorted based on this newly added property:

const data = [{"dislikes":[{"createDate":{"date":11,"day":0,"hours":18,"minutes":15,"month":10,"seconds":11,"time":1541956511001,"timezoneOffset":-60,"year":118}},{"createDate":{"date":11,"day":0,"hours":18,"minutes":15,"month":10,"seconds":11,"time":1541956511008,"timezoneOffset":-60,"year":118}}]},{"dislikes":[{"createDate":{"date":11,"day":0,"hours":18,"minutes":15,"month":10,"seconds":11,"time":1541956511011,"timezoneOffset":-60,"year":118}},{"createDate":{"date":11,"day":0,"hours":18,"minutes":15,"month":10,"seconds":11,"time":1541956511028,"timezoneOffset":-60,"year":118}}]}];

console.log(
  data
    //map and add newestDislike property
    .map((d) => ({

      ...d,
      
      //reduce and only takes the lowest time value
      newestDislike: (d.dislikes || []).reduce(

        (result, item) =>
          
          item.createDate.time < result
  
            ? item.createDate.time

            : result,

        Infinity, //defaults to infinity (if no dislikes)
      ),

    }))
    .sort((a, b) => 

      a.newestDislike - b.newestDislike),
);

If the dislikes in the user are already sorted by oldest date first then you can skip the map and reduce part. If a user can have empty dislikes or undefined then make sure to use a getter function with a default value to prevent any crashes in your code:

//gets a nested prop from object or returns defaultValue
const get = (o = {}, path, defaultValue) => {
  
  const recur = (o, path, defaultValue) => {

    if (o === undefined) return defaultValue;

    if (path.length === 0) return o;
    
    if (!(path[0] in o)) return defaultValue;

    return recur(o[path[0]], path.slice(1), defaultValue);
  
  };
  
  return recur(o, path, defaultValue);

};

console.log(
  
  data.sort(
    
    (a, b) =>
      
      get(
        
        a,
        
        ['dislikes', 0, 'createDate', 'time'],
        
        Infinity,
      
      ) -
      
      get(
        
        b,
        
        ['dislikes', 0, 'createDate', 'time'],
        
        Infinity,
      
      ),
     
   ),
 
 );

Answer №2

//Pass the array mentioned as users to the function sortDislikesForAllUsers below
let sortDislikesForAllUsers = function(users) {
    return users.map(user => {
        return {
            dislikes: user.dislikes.sort((dislikeA, dislikeB) => ((dislikeA.createDate.time < dislikeB.createDate.time) ? -1 : (dislikeA.createDate.time > dislikeB.createDate.time) ? 1 : 0))
        }
    })
}
//Pass the array returned above as input to the function sortUsers
let sortUsers = function(arrayOfSortedDislikesPerUser) {
    return arrayOfSortedDislikesPerUser.sort((userA, userB) => ((userA.dislikes[0].createDate.time < userB.dislikes[0].createDate.time) ? -1 : (userA.dislikes[0].createDate.time > userB.dislikes[0].createDate.time) ? 1 : 0))
}

let arrayOfSortedDislikesPerUser = sortDislikesForAllUsers(users);
let finalSortedArray = sortUsers(arrayOfSortedDislikesPerUser);
console.log(finalSortedArray);

Explanation:
sortDislikesForAllUsers method is used for sorting dislikes for each user individually.

sortUsers method sorts users based on the first dislike time obtained from the sorted dislikes array using the previous method

Easy peasy!

Run the code snippet below directly in your code:

let users = [{
        "dislikes": [
            {
                "createDate": {
                    "date": 11,
                    "day": 0,
                    "hours": 18,
                    "minutes": 15,
                    "month": 10,
                    "seconds": 11,
                    "time": 1541956511001,
                    "timezoneOffset": -60,
                    "year": 118
                },
            },
            {
                "createDate": {
                    "date": 11,
                    "day": 0,
                    "hours": 18,
                    "minutes": 15,
                    "month": 10,
                    "seconds": 11,
                    "time": 1541956511008,
                    "timezoneOffset": -60,
                    "year": 118
                },
            }
        ],
    },
    {
        "dislikes": [
            {
                "createDate": {
                    "date": 11,
                    "day": 0,
                    "hours": 18,
                    "minutes": 15,
                    "month": 10,
                    "seconds": 11,
                    "time": 1541956511011,
                    "timezoneOffset": -60,
                    "year": 118
                },
            },
            {
                "createDate": {
                    "date": 11,
                    "day": 0,
                    "hours": 18,
                    "minutes": 15,
                    "month": 10,
                    "seconds": 11,
                    "time": 1541956511028,
                    "timezoneOffset": -60,
                    "year": 118
                },
            }
        ],
    }]

    let sortDislikesForAllUsers = function(users) {
    return users.map(user => {
    return {
    dislikes: user.dislikes.sort((dislikeA, dislikeB) => ((dislikeA.createDate.time < dislikeB.createDate.time) ? -1 : (dislikeA.createDate.time > dislikeB.createDate.time) ? 1 : 0))
    }
    })
    }

    let sortUsers = function(arrayOfSortedDislikesPerUser) {
    return arrayOfSortedDislikesPerUser.sort((userA, userB) => ((userA.dislikes[0].createDate.time < userB.dislikes[0].createDate.time) ? -1 : (userA.dislikes[0].createDate.time > userB.dislikes[0].createDate.time) ? 1 : 0))
    }

    let arrayOfSortedDislikesPerUser = sortDislikesForAllUsers(users);
    let finalSortedArray = sortUsers(arrayOfSortedDislikesPerUser);
    console.log(finalSortedArray);

EDIT: Regarding @HMR's comment:
1. It alters the original array. If you want to avoid this, make a copy of the array before sorting.

let noRefCopy = new Array()
noRefCopy = noRefCopy.concat(originalArr)

Sort the copy and return it instead.

2. You can add checks for undefined etc if needed.

These concerns can be addressed if the question requires them specifically.

Cheers,
Kruthika

Answer №3

To effectively sort based on time, utilize the code snippet provided below:

function sortByTime(obj1, obj2){
  return obj1.time - obj2.time;
}

array.sort((obj1, obj2)=>{
  obj1.dislikes.sort(sortByTime);
  obj2.dislikes.sort(sortByTime);
  return obj1.dislikes[0].time - obj2.dislikes[0].time;
});

The concept of sorting by earliest time may not have been clear. The code demonstrated above arranges time values in ascending order.

REMINDER: It is important to note that the provided code does not address scenarios where a property could potentially be missing.

Answer №4

Here is an example of how you can use lodash.js to sort user dislikes based on their creation date:

_.each(users, (user) => { user.dislikes = _.sortBy(user.dislikes, 'createdDate.time'); });
users = _.sortBy(users, 'dislikes[0].createdDate.time');

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

Can you please explain how I can retrieve information from a Firebase collection using the NextJs API, Firebase Firestore, axios, and TypeScript?

I'm currently utilizing api routes within NextJS 13 to retrieve data from Firebase. The code for this can be found in api/locations.tsx: import { db } from "../../firebase"; import { collection, getDocs } from "firebase/firestore"; ...

Simply use `$timeout` inside the `$watch` method in AngularJS to create a chained

My goal is to link two $timeout functions inside a $watch. This $watch monitors user actions, and if any action is detected, both $timeout instances are canceled. Below is the code snippet outlining this scenario. .run(['$rootScope', '$loc ...

Angular sing ng-view to load images from a file

I am developing a single page app (index.html) with the following relevant sections: <!DOCTYPE html> <html> <head> <base href="/mi_ui/"> <link rel="stylesheet" type="text/css" href="assets/css/bootstrap.min.css"> <script s ...

In AngularJS, encountering difficulties when trying to append an object to the end of the scope due to persistent data updates

Whenever a user submits a form, the fields are stored in a variable called $scope.params. In order to keep track of all submitted data, I am attempting to save them in an object named $scope.history. My current approach involves using the following code: ...

Creating a multi-dimensional array in order to store multiple sets of data

To generate a multidimensional array similar to the example below: var serviceCoors = [ [50, 40], [50, 50], [50, 60], ]; We have elements with latitude and longitude data: <div data-latitude="10" data-longitude="20" clas ...

What sets using int versus size_t apart when initializing arrays in C?

During my exploration of buffered input, I crafted a brief C program in accordance with the C90 standard: #include <stdio.h> #include <stdlib.h> #define MAXLINE 10 int getLine(char s[]) { int ch; int chCount; for (chCount = 0; (c ...

Angular 2 counterpart to the renderToString function in React

I need to find the equivalent in Angular 2 of react-dom/server.renderToString import { renderToString } from 'react-dom/server'; // Render the component to a string const html = renderToString( <App /> ); Can someone provide a simpl ...

Using Javascript to retrieve the childNode

I have encountered a challenge that I am struggling to overcome. My issue involves utilizing a dynamically generated table with 4 columns: a checkbox, text values, and a hidden input. echo "<tr><td><div class='input-containerh'> ...

``Symmetric matrix exhibits poor diagonalization due to its ill-conditioned nature. While the eigenvalues are satisfactory, the

I am facing a challenge of diagonalizing an ill-conditioned sparse matrix with very small values. I have successfully achieved this using C++ with LAPACK and now I am hoping to replicate the same in Julia. However, there is a discrepancy in the results obt ...

Modifying the value of a property in one model will also result in the modification of the same

As a beginner with Vue, I am looking to allow users to add specific social media links to the page and customize properties like text. There are two objects in my data - models and defaults. The defaults object contains selectable options for social media ...

Strategies for aligning tooltips with the locations of dragged elements

One of my projects involves a simple drag element example inspired by Angular documentation. The example features a button that can be dragged around within a container and comes with a tooltip. <div class="example-boundary"> <div ...

What is the best way to provide a static file to an individual user while also sharing its file path

I have integrated jsmodeler (https://github.com/kovacsv/JSModeler) into my website to display 3D models. Currently, users can only select a file using a filepicker or by entering the path in the URL (e.g., http://localhost:3000/ModelView#https://cdn.rawgit ...

Exploring the function of variables in VueJS

I'm facing a tricky issue with VueJS as I am still getting acquainted with it. My objective is to access and modify variables within the data function, but so far, I haven't been successful. The problematic line: console.log('item: ' ...

Retrieving sender information using jQuery within a Bootstrap iframe modal

I'm trying to integrate a Google Map into a Bootstrap 4.0 Beta modal window. After coming across this helpful post and implementing the code successfully, I realized I lack the necessary expertise in jQuery to achieve the specific functionality I des ...

IE8 and IE9 encountering "Access is denied" error due to XML causing XDomainRequest (CORS) issue

Sorry if this seems repetitive, but I am unable to find a definitive answer to similar questions. Whenever I attempt to make a CORS request for XML, I consistently encounter an "Access is denied" JavaScript error in IE8. The code I am using is based on t ...

Morris.js is throwing an error message, stating "Uncaught TypeError: Unable to access the 'label' property as it

I have successfully implemented a bar chart along with a date picker using Bootstrap. The bar chart loads data accurately when selecting a specific day. However, upon inspecting the developer tools, I encounter the following errors: Uncaught Type Error: C ...

Retrieving a JSON object using a for loop

I'm working on a basic link redirector project. Currently, I have set up an Express server in the following way: const express = require('express'); const app = express() const path = require('path'); const json = require('a ...

What is the best way to convert an SVG string to an SVG file with Python?

After using AJAX, I am able to send an SVG image to Django using the function below: function uploadSVG(){ var svgImage = document.getElementById("SVG"); var serializer = new XMLSerializer(); var svgStr = serializer.serializeToStrin ...

Invoking one service from another service in AngularJS

I'm trying to access a service from another service and use the returned object for some operations. However, I keep encountering a TypeError: getDefinitions is not a function error. Here is the code for my services and controller: definitions.servi ...

How to Retrieve the Selected Value from an Array of Objects using Angular UI Typeahead

I am currently utilizing the typeahead angular bootstrap directive, which I find to be quite useful. However, I am facing a challenge regarding obtaining the select value when using it with an array of objects (which is necessary for a custom template). Th ...