首页 > 解决方案 > 关于使用时间戳对数组进行排序的 javascript 问题

问题描述

我不太熟悉在 Javascript 中对数组和对象进行排序,并且想知道在某些条件下如何对对象进行排序。最终目标是在日历功能中使用这种排序。

举个例子,假设我们有一个类似下面代码片段的情况:

$(document).on('mouseup', '.event', function(){
  var box_date    = $(this).attr('date');
  var param       = [];
  $(`.day[date=${box_date}] .event`).each(function(){
    var box         = $(this);
    var row         = {};
    var time_start  = box.attr('time_start');
    var time_end    = box.attr('time_end');
    var id_event    = box.attr('id_event');
    var time_diff   = timeDiff(time_start, time_end);
    row.time_start  = time_start;
    row.time_end    = time_end;
    row.diff        = time_diff;
    row.id_event    = id_event;
    param.push(row);
  })
  console.log(param);
  param.sort((a, b) => {
        if (a.time_start < b.time_start){
            return -1;
        } else if (a.time_start > b.time_start){
            return 1;
        } else if (b.diff - a.diff) return -1;
        return 1;
    });
  console.log(param);
})

function timeDiff(time_start, time_end){
    var today = new Date(),
            month = today.getMonth() + 1,
            day   = today.getDate(),
            year  = today.getFullYear();
      
    month     = month.toString();
    month     = month.padStart(2,'0');
    day       = day.toString();
    day       = day.padStart(2, '0');
    date      = [year, month, day].join('-');
    var date1 = `${date} ${time_start}`;
    var date2 = `${date} ${time_end}`;
    date1     = new Date(date1);
    date2     = new Date(date2);

    var diff_time = Math.abs(date1 - date2);
  // convert the time diff from ms to min
    diff_time = diff_time / (1000 * 60);
    return diff_time;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="day" date="2021-02-21">
 <div class="event" id_event="1" date="2021-02-21" time_start="10:00" time_end="10:30">Val1</div>
 <div class="event" id_event="2" date="2021-02-21" time_start="10:00" time_end="11:00">Val2</div>
 <div class="event" id_event="3" date="2021-02-21" time_start="10:00" time_end="12:00">Val3</div>
 <div class="event" id_event="4" date="2021-02-21" time_start="09:30" time_end="12:00">Val4</div>
 <div class="event" id_event="5" date="2021-02-21" time_start="13:00" time_end="15:00">Val5</div>
</div>

让我们不要关注如何将数据放入数组或对象中,而是关注将数据排序为正确顺序/格式的过程。

事件编号 日期 时间开始 时间结束 分钟
1 2021-02-21 10:00 10:30 30
2 2021-02-21 10:00 11:00 60
3 2021-02-21 10:00 12:00 120
4 2021-02-21 09:30 12:00 150
5 2021-02-21 13:00 15:00 120

获取数据时,它们按上述顺序显示,但由于用户可以移动和扩展/缩小每个元素,因此我需要相应地设置事件 div 的 z-index 以进行样式设置。

这意味着一旦元素的定位完成并且原始数据根据上面的数据,我需要根据以下条件对数据进行排序:

  1. 最早的开始日期为第一个。
  2. 如果 2 个元素具有相同的开始日期,则持续时间较长的元素优先于另一个元素

通过遵循该逻辑,上述结果应遵循以下顺序

事件编号 日期 时间开始 时间结束 分钟
4 2021-02-21 09:30 12:00 150
3 2021-02-21 10:00 12:00 120
2 2021-02-21 10:00 11:00 60
1 2021-02-21 10:00 10:30 30
5 2021-02-21 13:00 15:00 120

我已经用一个工作示例更新了片段,但如果有更好的方法来完成同样的事情,请告诉我。

/C

标签: javascriptarrayssortingjquery-multisortable

解决方案


您可以执行与使用 SQL 相同的操作。

FROM events
ORDER BY time_start ASC, time_end DESC

在 JavaScript 中,这可以通过以下方式完成:

events.sort((a, b) => {
  // time_start ascending
  if (a.time_start < b.time_start) return -1;
  if (a.time_start > b.time_start) return  1;
  // time_end descending
  if (a.time_end < b.time_end) return  1;
  if (a.time_end > b.time_end) return -1;
  // equal
  return 0;
});

请注意,这是基于字符比较的,因为您的时间是零填充的,并且是 24 小时制。4:20这在应该是的时间内失败了04:20。如果没有0前面,它将被认为比例如因为(第一个字符)晚。12:424 (code 0x34) > 1 (code 0x31)

我还添加了一个更具描述性的选项,但这确实引入了一些辅助函数。

$(document).on('mouseup', '.event', function(){
  var box_date    = $(this).attr('date');
  var param       = [];
  $(`.day[date=${box_date}] .event`).each(function(){
    var box         = $(this);
    var row         = {};
    var time_start  = box.attr('time_start');
    var time_end    = box.attr('time_end');
    var id_event    = box.attr('id_event');
    row.time_start  = time_start;
    row.time_end    = time_end;
    row.id_event    = id_event;
    param.push(row);
  })
  console.log(param);
  param.sort((a, b) => {
    // time_start ascending
    if (a.time_start < b.time_start) return -1;
    if (a.time_start > b.time_start) return  1;
    // time_end descending
    if (a.time_end < b.time_end) return  1;
    if (a.time_end > b.time_end) return -1;
    // equal
    return 0;
  });
  console.log(param);
  // or if you don't mind introducing some helpers
  param.sort(asc(event => event.time_start).chain(desc(event => event.time_end)));
  console.log(param);
})

// helpers
function asc(mapFn) {
  return attachComparatorMethods(function (a, b) {
    a = mapFn(a);
    b = mapFn(b);
    return -(a < b) || +(a > b);
  });
}

function desc(mapFn) {
  const comparator = asc(mapFn);
  return attachComparatorMethods(function (a, b) {
    return comparator(b, a);
  });
}

function attachComparatorMethods(comparator) {
  return Object.assign(comparator, {
    chain(comparator) {
      return attachComparatorMethods((a, b) => this(a, b) || comparator(a, b));
    }
  });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="day" date="2021-02-21">
  <div class="event" id_event="1" date="2021-02-21" time_start="10:00" time_end="10:30">Val1</div>
  <div class="event" id_event="2" date="2021-02-21" time_start="10:00" time_end="11:00">Val2</div>
  <div class="event" id_event="3" date="2021-02-21" time_start="10:00" time_end="12:00">Val3</div>
  <div class="event" id_event="4" date="2021-02-21" time_start="09:30" time_end="12:00">Val4</div>
  <div class="event" id_event="5" date="2021-02-21" time_start="13:00" time_end="15:00">Val5</div>
</div>

如果您在理解asc帮助程序时遇到问题,可能是由于以下行:

return -(a < b) || +(a > b);

也可以写成:

if (a < b) return -1;
if (a > b) return  1;
return 0;

推荐阅读