简体   繁体   中英

Sort an array of objects based on times string values?

I have an array of objects

var data =[
  {
    "avail": "3 Bookings Available" 
    "time": "05:00 PM to 06:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "09:00 AM to 10:00 AM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "04:00 PM to 05:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "03:00 PM to 04:00 PM",
    "date": "2018-01-30"
  }];

I want to sort data by its time string value so that the required output becomes like this below:

 [{
    "avail": "3 Bookings Available" 
    "time": "09:00 AM to 10:00 AM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "03:00 PM to 04:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "04:00 PM to 05:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "05:00 PM to 06:00 PM",
    "date": "2018-01-30"
  }]

I have used the sort function with String #localeCompare but still i am not getting the required output

data.sort(function(a,b){
  return a.time.localeCompare(b.time);
});
console.log(data);

even i used the String#slice() method by which i can be used to generate the valid date string using '1970/01/01' as an arbitrary date still i am getting the required out can anyone give me the way by which i can get the output in this manner Thanks in advance.

data.sort(function(a, b) {
  return Date.parse('1970/01/01 ' + a.time.slice(0, -2) + ' ' + a.time.slice(-2)) - Date.parse('1970/01/01 ' + b.time.slice(0, -2) + ' ' + b.time.slice(-2))
});

Example:

 var data = [{ "avail": "3 Bookings Available", "time": "05:00 PM to 06:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "09:00 AM to 10:00 AM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "04:00 PM to 05:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "03:00 PM to 04:00 PM", "date": "2018-01-30" } ]; data.sort(function(a, b) { return Date.parse('1970/01/01 ' + a.time.slice(0, -2) + ' ' + a.time.slice(-2)) - Date.parse('1970/01/01 ' + b.time.slice(0, -2) + ' ' + b.time.slice(-2)) }); console.log(data) 

I'd have a functon to turn those times into minutes-since-midnight, something roughly like:

function parseTime(time) {
  var parts = time.match(/^(\d{2}):(\d{2}) (AM|PM)/i);
  if (!parts) {
    return NaN;
  }
  var adjust = parts[3].toUpperCase() == "PM" ? 12 : 0;
  return (parseInt(parts[1], 10) + adjust) * 60 + parseInt(parts[2], 10);
}

Then the sorting is straightforward:

data.sort(function(a, b) {
  return parseTime(a.time) - parseTime(b.time);
});

Example:

 var data =[ { "avail": "3 Bookings Available", "time": "05:00 PM to 06:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "09:00 AM to 10:00 AM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "04:00 PM to 05:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "03:00 PM to 04:00 PM", "date": "2018-01-30" }]; function parseTime(time) { var parts = time.match(/^(\\d{2}):(\\d{2}) (AM|PM)/i); if (!parts) { return NaN; } var adjust = parts[3].toUpperCase() == "PM" ? 12 : 0; return (parseInt(parts[1], 10) + adjust) * 60 + parseInt(parts[2], 10); } data.sort(function(a, b) { return parseTime(a.time) - parseTime(b.time); }); console.log(data); 
 .as-console-wrapper { max-height: 100% !important; } 

Classic divide-and-conquer (eg, break the problem into smaller pieces).

This works (after adding a missing comma):

 var data = [{ "avail": "3 Bookings Available", "time": "05:00 PM to 06:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "09:00 AM to 10:00 AM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "04:00 PM to 05:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "03:00 PM to 04:00 PM", "date": "2018-01-30" } ]; data.sort(function(a, b) { const [afrom, ato]=a.time.split(" to "); const [bfrom, bto]=b.time.split(" to "); return Date.parse(a.date + " " + afrom) - Date.parse(b.date + " "+ bfrom); }); console.log(data) 

Normal string comparison is fine for this, but you need to re-arrange the AM or PM at the beginning of the time string(use String#replace method for that).

 var data = [{ "avail": "3 Bookings Available", "time": "05:00 PM to 06:00 PM", "date": "2018-01-30"}, { "avail": "3 Bookings Available", "time": "09:00 AM to 10:00 AM", "date": "2018-01-30"}, { "avail": "3 Bookings Available", "time": "04:00 PM to 05:00 PM", "date": "2018-01-30"}, { "avail": "3 Bookings Available", "time": "03:00 PM to 04:00 PM", "date": "2018-01-30"}]; data.sort(function(a, b) { // compare the date string return a.date.localeCompare(b.date) || // in case they are equal then compare time string // after converting the format timeFormat(a).localeCompare(timeFormat(b)) }); // function for formating the time string function timeFormat(o) { // reposition the AM or PM at the beginning of time // for string comparison return o.time.replace(/(\\d{2}:\\d{2}\\s)(AM|PM)/g, '$2$1'); } console.log(data); 

您可以合并日期和时间,并创建一个日期对象,您可以获取自1970年以来的时间(以毫秒为单位),比较这些数字并相应地对数组进行排序。

With a helper function toMilitary you can change the time to a number between 0 and 2359. Then map the original data to military time and index. Then sort on the military time. And at last reduce the result using the indexes of the sorted set to pick items from the original data.

Following code does not mutate any of the original data.

  const data =[ { "avail": "3 Bookings Available", "time": "05:00 PM to 06:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "09:00 AM to 10:00 AM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "04:00 PM to 05:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "03:00 PM to 04:00 PM", "date": "2018-01-30" } ]; const toMilitary = timeString => { const time = timeString.slice(0,8); const amPm = time.slice(-2).toLowerCase(); const timeNumber = parseInt(time.replace(/[^0-9]/g,""),10); return (amPm==="pm")?timeNumber+1200:timeNumber; }; const sortedData = data .map((d,index)=>[ toMilitary(d.time), index ]) .sort((a,b)=>a[0]-b[0]) .reduce( (all,[_,index])=> all.concat([data[index]]), [] ); console.log(JSON.stringify(sortedData,undefined,2)) 

I like mplungjan way and it includes the date. It will call the parsing date and time function many times while sorting so I've implemented it instead of military from the previous. First calculate full date and time for all objects and pair with index, then sort, then pick items from data using the indexes of the sorted result:

 const data =[ { "avail": "3 Bookings Available", "time": "05:00 PM to 06:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "09:00 AM to 10:00 AM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "04:00 PM to 05:00 PM", "date": "2018-01-30" }, { "avail": "3 Bookings Available", "time": "03:00 PM to 04:00 PM", "date": "2018-01-30" } ]; const fullDate = item => { const [from, to]=item.time.split(" to "); return Date.parse(item.date + " " + from); }; const sortedData = data .map((d,index)=>[ fullDate(d),index ]) .sort((a,b)=>a[0]-b[0]) .reduce( (all,[_,index])=> all.concat([data[index]]), [] ); console.log(JSON.stringify(sortedData,undefined,2)) 

Here's a simple example using moment.js to parse with a custom format :

 var data = [ { "time": "05:00 PM to 06:00 PM", "date": "2018-01-30" }, { "time": "09:00 AM to 10:00 AM", "date": "2018-01-30" }, { "time": "04:00 PM to 05:00 PM", "date": "2018-01-30" }, { "time": "03:00 PM to 04:00 PM", "date": "2018-01-30" } ]; data.sort(function(a, b) { let format = "YYYY-MM-DD hh:mm A"; let ma = moment(a.date + " " + a.time, [format]) let mb = moment(b.date + " " + b.time, [format]) return ma.diff(mb); }); console.log(data); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script> 

Here's another example which also includes the end time in the sort (if two start date/times are equal):

 var data = [ { "time": "09:00 PM to 06:00 PM", "date": "2018-01-30" }, { "time": "09:00 PM to 10:00 AM", "date": "2018-01-30" }, { "time": "09:00 PM to 05:00 PM", "date": "2018-01-30" }, { "time": "09:00 PM to 04:00 PM", "date": "2018-01-30" } ]; data.sort(function(a, b) { let format = "YYYY-MM-DD hh:mm A"; let ma = moment(a.date + " " + a.time, [format]) let mb = moment(b.date + " " + b.time, [format]) let diff = ma.diff(mb); if(diff === 0) { ma = moment(a.date + " " + a.time.substring(12), [format]) mb = moment(b.date + " " + b.time.substring(12), [format]) diff = ma.diff(mb); } return diff; }); console.log(data); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM