0

For the following array-object-thing structure:

Events : {
    events : [
        {
          startDTG : {day: 0, month: 0, year: 0, time: "" },
          endDTG : {day: 0, month: 0, year: 0, time: "" },
          mode: ""
        },
        ...
    ],
    blah...,
    blah...,
    blah...
}

I am struggling to find a more efficient way to sort the events objects based on the startDTG key (Date-Time Group). Currently I use the following, but I feel there has to be a better way to do it!

SortEvents: function() {
    this.Events.events.sort(function(a, b){return a.startDTG.time - b.startDTG.time});
    this.Events.events.sort(function(a, b){return a.startDTG.day - b.startDTG.day});
    this.Events.events.sort(function(a, b){return a.startDTG.month - b.startDTG.month});
    this.Events.events.sort(function(a, b){return a.startDTG.year - b.startDTG.year});
},

Edit 1: The desire is to be sorted by Year > Month > Day > Time

I am at a critical point in which I am to abandon this custom DTG in the name of efficiency it is needed. I can post the entire code if requested, but might not make total sense as it is JS written to work within a Proprietary Control system called "Medialon"

Edit 2: Added a quick-made JSON code dump below to assist with readability of structure. Ignore the fact they are all "strings" it is how Medialon stringifies for persistence

{
  "events": [
    {
      "startDTG": {
        "day": "8",
        "month": "2",
        "year": "2019",
        "time": "06:35",
        "dayName": "5"
      },
      "endDTG": {
        "day": "9",
        "month": "2",
        "year": "2019",
        "time": "08:35",
        "dayName": "6"
      },
      "mode": "1"
    },
    {
      "startDTG": {
        "day": "27",
        "month": "2",
        "year": "2019",
        "time": "17:35",
        "dayName": "3"
      },
      "endDTG": {
        "day": "28",
        "month": "2",
        "year": "2019",
        "time": "06:35",
        "dayName": "4"
      },
      "mode": "1"
    },
    {
      "startDTG": {
        "day": "1",
        "month": "2",
        "year": "2019",
        "time": "14:35",
        "dayName": "5"
      },
      "endDTG": {
        "day": "2",
        "month": "2",
        "year": "2019",
        "time": "12:35",
        "dayName": "6"
      },
      "mode": "1"
    }
  ],
11
  • 1
    In the above, all your going to end up with is the events sorted by year,. So a more efficient way, is to not do the other sorts.. :) I'm assuming your wanting to sort by year then month, then day then time, but that's not how you do a compound sort. Commented Feb 4, 2019 at 21:12
  • Can you clean up the code sample a bit? It's hard to tell what's an array and what's an object. I think you are missing a few {}... Commented Feb 4, 2019 at 21:12
  • You can separate the sorting criteria with || i.e. this.Events.events.sort(function(a, b){return a.startDTG.year- b.startDTG.year || a.startDTG.month- b.startDTG.month || ... //etc}) Commented Feb 4, 2019 at 21:13
  • 1
    @Keith: because pretty much all sort implementations are now stable, this will do what's desired: sort by year first, then month, then day. (Time as a string is more problematic). This is definitely not the most efficient, though. Commented Feb 4, 2019 at 21:13
  • 1
    @ScottSauyet Edge doesn't have stable sort if that's an issue, and neither did Chrome until recently. And ES7 doesn't state a stable sort is a requirement, so I'd be very careful relying on such behaviour. Commented Feb 4, 2019 at 21:28

2 Answers 2

1

I'm still not quite sure of your data structure, but something like this should be close:

const events = [
  {name: 'a', startDTG: {year: 2019, month: 1,  day: 4,  time: '14:21:46'}, endDTG: ''},
  {name: 'b', startDTG: {year: 2018, month: 10, day: 7,  time: '12:13:59'}, endDTG: ''},
  {name: 'c', startDTG: {year: 2019, month: 1,  day: 4,  time: '09:23:51'}, endDTG: ''},
  {name: 'd', startDTG: {year: 2019, month: 1,  day: 2,  time: '15:02:36'}, endDTG: ''},
  {name: 'e', startDTG: {year: 2017, month: 9,  day: 17, time: '03:25:29'}, endDTG: ''},
  {name: 'f', startDTG: {year: 2017, month: 9,  day: 17, time: '03:25:28'}, endDTG: ''},
  {name: 'g', startDTG: {year: 2018, month: 4,  day: 14, time: '11:07:42'}, endDTG: ''},
]

events.sort((
  {startDTG: {year: y1, month: m1, day: d1, time: t1}}, 
  {startDTG: {year: y2, month: m2, day: d2, time: t2}}
) => 
  // y1 - y2 || m1 - m2 || d1 - d2 || (t1 < t2 ? -1 : t1 > t2 ? 1 : 0)           
  y1 - y2 || m1 - m2 || d1 - d2 || t1.localeCompare(t2)
)

console.log(events)

Sign up to request clarification or add additional context in comments.

6 Comments

Yeah, that's much better. I wonder if localeCompare might be easier to read than the ternary for the times.
@MarkMeyer: yes, that definitely looks better.
@MarkMeyer The OP mentioned efficient, so is maybe looking for the fastest. A tenery should be quicker, and a quick benchmark make localeCompare about 70% slower.
Well, they're both there for the OP to choose from. Either way, this should likely be quite a bit faster than performing four separate sorts.
@ScottSauyet So there is a little bit of fenangling I have to do to get JS to work in this program. For the alias portion you did right after the .sort(), what is the technical name for it so I can read up on it a bit more. It doesn't work as a drop in snippit though it looks promising!
|
1

Another solution could be mapping your data to a Date() and then comparing the milliseconds returned with getTime().

let data = {
  "events": [
    {
      "startDTG": {"day": "8", "month": "2", "year": "2019", "time": "6:35", "dayName": "5"},
      "endDTG": {"day": "9", "month": "2", "year": "2019", "time": "6:35", "dayName": "6"},
      "mode": "1"
    },
    {
      "startDTG": {"day": "27", "month": "2", "year": "2019", "time": "6:35", "dayName": "3"},
      "endDTG": {"day": "28", "month": "2", "year": "2019", "time": "6:35", "dayName": "4"},
      "mode": "1"
    },
    {
      "startDTG": {"day": "1", "month": "2", "year": "2019", "time": "6:35", "dayName": "5"},
      "endDTG": {"day": "2", "month": "2", "year": "2019", "time": "6:35", "dayName": "6"},
      "mode": "1"
    }
  ]
};

const startDTGToStr = o => `${o.year}-${o.month}-${o.day} ${o.time}`

data.events.sort((a, b) =>
{
    a = new Date(startDTGToStr(a.startDTG));
    b = new Date(startDTGToStr(b.startDTG));
    return a.getTime() - b.getTime();
});

console.log(data.events);

1 Comment

Although this is going to be faster than sorting an array 4 times, there is a bit of overhead in creating a Date object for every compare. And as such is slower than doing a compound compare like @Scott shows below. But if the OP had stored a DateTime in the first place, this would be the way to go.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.