Home > Software engineering >  Sorting of an array of objects by multiple fields in JavaScript varies based on object position in t
Sorting of an array of objects by multiple fields in JavaScript varies based on object position in t

Time:11-05

While researching on the mechanism for sorting arrays in JavaScript by multiple properties/fields/attributes, I've come across this article. For my personal project I have utilized the solution offered by @chriskelly.

function comparator(attrs) {
    return function (v1, v2) {
        return attrs
            .map(function (fld) {
                var ad = 1;
                if (fld[0] === '-') {
                   ad = -1;
                   fld = fld.substring(1);
                }
                if (v1[fld] > v2[fld]) return ad;
                if (v1[fld] < v2[fld]) return -(ad);
                return 0;
            })
            .reduce(function nonZero (v3, v4) {
                return v3 ? v3 : v4;
            }, 0);
    };
}

My input array is the following:

[{"name":"Pass9884881","fld1d":10,"fld2d":25,"fld4d":383,"fld3d":626490,"fld5a":0,"date":"09/27/2021","time":"18:23:31"},
 {"name":"Driver1","fld1d":"10","fld2d":25,"fld4d":356,"fld3d":559650,"fld5a":0,"date":"10/18/2021","time":"14:48:17"},
 {"name":"Driver321","fld1d":10,"fld2d":22,"fld4d":346,"fld3d":554400,"fld5a":1,"date":"08/08/2021","time":"22:35:03"},
 {"name":"Driverxyz","fld1d":9,"fld2d":25,"fld4d":350,"fld3d":497190,"fld5a":0,"date":"07/26/2021","time":"14:23:33"},
 {"name":"Pass1974761","fld1d":"9","fld2d":25,"fld4d":316,"fld3d":477290,"fld5a":0,"date":"10/11/2021","time":"19:20:33"},
 {"name":"Pass7374147","fld1d":"9","fld2d":23,"fld4d":279,"fld3d":376750,"fld5a":0,"date":"10/10/2021","time":"20:13:15"},
 {"name":"Driver0","fld1d":8,"fld2d":25,"fld4d":286,"fld3d":435940,"fld5a":0,"date":"07/26/2021","time":"12:31:42"},
 {"name":"Pass1536735","fld1d":"8","fld2d":25,"fld4d":236,"fld3d":329880,"fld5a":0,"date":"10/09/2021","time":"17:19:14"},
 {"name":"#xxxxyyyy","fld1d":"10","fld2d":25,"fld4d":329,"fld3d":500440,"fld5a":0,"date":"11/04/2021","time":"00:04:17"},
 {"name":"Pass7668209","fld1d":"8","fld2d":24,"fld4d":203,"fld3d":267150,"fld5a":0,"date":"10/09/2021","time":"00:22:18"}]

It meant to be sorted by fld1d (desc), fld2d (desc), fld3d (desc), fld4d (desc), fld5a (asc), date (asc) and time (asc). When the object with "name":"#xxxxyyyy" is placed the last or next to the last in the input data (gets read in from an external file in the code), the resulting sorted array appears incorrect: Incorrectly sorted array

However, if I move that object in the input file to the 8th position (out of 10) or above, the resulting sorted array is correct: Correctly sorted array

I ought to admit, I am not a professional developer - just an interested party who somewhat learnt to follow examples, and I'm having hard time explaining the discrepancy in the results.

Suggestions would be greatly appreciated.

CodePudding user response:

You could take a simplified approach and chain all sorting crieria by taking the delta or use a string comparison.

const
    getISO = (date, time) => `${date.slice(3, 5)}-${date.slice(0, 2)}-${date.slice(6, 10)}T${time}`;
    data = [{ name: "Pass9884881", fld1d: 10, fld2d: 25, fld4d: 383, fld3d: 626490, fld5a: 0, date: "09/27/2021", time: "18:23:31" }, { name: "Driver1", fld1d: "10", fld2d: 25, fld4d: 356, fld3d: 559650, fld5a: 0, date: "10/18/2021", time: "14:48:17" }, { name: "Driver321", fld1d: 10, fld2d: 22, fld4d: 346, fld3d: 554400, fld5a: 1, date: "08/08/2021", time: "22:35:03" }, { name: "Driverxyz", fld1d: 9, fld2d: 25, fld4d: 350, fld3d: 497190, fld5a: 0, date: "07/26/2021", time: "14:23:33" }, { name: "Pass1974761", fld1d: "9", fld2d: 25, fld4d: 316, fld3d: 477290, fld5a: 0, date: "10/11/2021", time: "19:20:33" }, { name: "Pass7374147", fld1d: "9", fld2d: 23, fld4d: 279, fld3d: 376750, fld5a: 0, date: "10/10/2021", time: "20:13:15" }, { name: "Driver0", fld1d: 8, fld2d: 25, fld4d: 286, fld3d: 435940, fld5a: 0, date: "07/26/2021", time: "12:31:42" }, { name: "Pass1536735", fld1d: "8", fld2d: 25, fld4d: 236, fld3d: 329880, fld5a: 0, date: "10/09/2021", time: "17:19:14" }, { name: "#xxxxyyyy", fld1d: "10", fld2d: 25, fld4d: 329, fld3d: 500440, fld5a: 0, date: "11/04/2021", time: "00:04:17" }, { name: "Pass7668209", fld1d: "8", fld2d: 24, fld4d: 203, fld3d: 267150, fld5a: 0, date: "10/09/2021", time: "00:22:18" }],

data.sort((a, b) =>
    b.fld1d - a.fld1d ||
    b.fld2d - a.fld2d ||
    b.fld3d - a.fld3d ||
    b.fld4d - a.fld4d ||
    a.fld5a - b.fld5a ||
    getISO(a.date, a.time).localeCompare(getISO(b.date, b.time))
);

console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related