【问题标题】:Sort Array by two dates and rules按两个日期和规则对数组进行排序
【发布时间】:2018-01-14 18:48:55
【问题描述】:

我正在构建一个事件列表日历。事件具有开始日期和结束日期,日期以 YYYYMMDD 格式存储。事件列表按天查看,事件可以是一天,也可以是多天。

事件当前存储在一个数组中,有start_dateend_date

我该怎么做:

  • 将所有从当前日期开始的事件移动到顶部 数组。
  • 然后按开始日期对事件进行排序
  • 然后按结束日期对事件进行排序

看到了这个question,但我在想如何建立上面的逻辑。

【问题讨论】:

  • 你想要三种排序方式还是所有这些规则合二为一?

标签: php arrays sorting usort


【解决方案1】:

将任何从当前日期开始的事件移到数组的顶部,但让其他事件保持原样!

$today = date('Ymd',strtotime('today'));
usort($events,function($a,$b) use($today){
  if($a['start_date'] === $today && $b['start_date'] != $today){return -1;}
  else if($b['start_date'] === $today && $a['start_date'] != $today){return 1;}
  else {return strnatcmp($a['start_date'],$b['start_date']);}
});

按开始日期对事件进行排序

usort($events,function($a,$b){
  return strnatcmp($a['start_date'],$b['start_date']);
});

按结束日期对事件进行排序

usort($events,function($a,$b){
  return strnatcmp($a['end_date'],$b['end_date']);
});

编辑一些测试数据:

//example works best if today is 20170810
$events = array(
  array(
    'name' => 'a',
    'start_date' => '20170810',
    'end_date' => '20170811',
  ),
  array(
    'name' => 'b',
    'start_date' => '20170810',
    'end_date' => '20170810',
  ),
  array(
    'name' => 'c',
    'start_date' => '20170607',
    'end_date' => '20170608',
  ),
  array(
    'name' => 'd',
    'start_date' => '20170607',
    'end_date' => '20170607',
  ),
  array(
    'name' => 'e',
    'start_date' => '20170810',
    'end_date' => '20170812',
  ),
  array(
    'name' => 'f',
    'start_date' => '20170807',
    'end_date' => '20170817',
  ),
);
print_r($events);

编辑:全部一起:事件按“今天开始吗?”、“开始日期”、“结束日期”排序

$today = date('Ymd',strtotime('today'));
usort($events,function($a,$b) use($today){
  //one of them starts today
  if($a['start_date'] === $today && $b['start_date'] != $today){return -1;}
  else if($b['start_date'] === $today && $a['start_date'] != $today){return 1;}
  //both or neither start today, compare start_date
  else {
    if($a['start_date'] != $b['start_date']){
      //start_dates differ, order by them
      return strnatcmp($a['start_date'],$b['start_date']);
    } else {
      //start dates are the same, order by end_date
      return strnatcmp($a['end_date'],$b['end_date']);
    }
  }
});

print_r($events);

编辑:正在进行中事件按“他们目前正在进行吗?”、“开始日期”、“结束日期”排序

$today = date('Ymd',strtotime('today'));
//function compares two elements to decide their position relative to each other
usort($events,function($a,$b) use($today){
  //check if event is currently ongoing
  //starts or ends today or today is between start and end
  $ongoing = function($event) use($today){
    //this is the simplest form I could think of for the check
    return (strnatcmp($event['start_date'],$today) < 1 && strnatcmp($today,$event['end_date']) < 1);
  };
  $startstoday = function($event) use($today){
    return $event['start_date'] === $today;
  };
  //only one of them is ongoing
  if($ongoing($a) && !$ongoing($b)){return -1;}
  else if($ongoing($b) && !$ongoing($a)){return 1;}
  //both or neither are ongoing, compare start_date
  else {
    if($a['start_date'] != $b['start_date']){
      //start_dates differ, order by them
      return strnatcmp($a['start_date'],$b['start_date']);
    } else {
      //start dates are the same, order by end_date
      return strnatcmp($a['end_date'],$b['end_date']);
    }
  }
});

print_r($events);

编辑:今天开始并进行中事件按“今天开始吗?”、“目前正在进行吗?”、“开始日期”、“结束日期”

$today = date('Ymd',strtotime('today'));
//function compares two elements to decide their position relative to each other
usort($events,function($a,$b) use($today){
  //check if event is currently ongoing
  //starts or ends today or today is between start and end
  $ongoing = function($event) use($today){
    //this is the simplest form I could think of for the check
    return (strnatcmp($event['start_date'],$today) < 1 && strnatcmp($today,$event['end_date']) < 1);
  };
  //only one of them is ongoing
  if($ongoing($a) && !$ongoing($b)){return -1;}
  else if($ongoing($b) && !$ongoing($a)){return 1;}
  //both are ongoing
  else if($ongoing($a) && $ongoing($b)){
    //one starts today
    if($a['start_date'] === $today && $b['start_date'] != $today){return -1;}
    else if($b['start_date'] === $today && $a['start_date'] != $today){return 1;}
    //both start today
    else if($a['start_date'] === $today && $b['start_date'] === $today){
      return strnatcmp($a['end_date'],$b['end_date']);
    }
    //none starts today
    else {
      if($a['start_date'] != $b['start_date']){
        //start_dates differ, order by them
        return strnatcmp($a['start_date'],$b['start_date']);
      } else {
        //start dates are the same, order by end_date
        return strnatcmp($a['end_date'],$b['end_date']);
      }
    }
  } else {
    //neither are ongoing, compare start_date
    if($a['start_date'] != $b['start_date']){
      //start_dates differ, order by them
      return strnatcmp($a['start_date'],$b['start_date']);
    } else {
      //start dates are the same, order by end_date
      return strnatcmp($a['end_date'],$b['end_date']);
    }
  }
});

print_r($events);

最后一个可以简化为:

$today = date('Ymd',strtotime('today'));
usort($events,function($a,$b) use($today){
  $ongoing = function($event) use($today){
    return (strnatcmp($event['start_date'],$today) < 1 && strnatcmp($today,$event['end_date']) < 1);
  };
  if($ongoing($a)){
    if(!$ongoing($b)){return -1;}
    else {
      if($a['start_date'] === $today && $b['start_date'] != $today){return -1;}
      else if($b['start_date'] === $today && $a['start_date'] != $today){return 1;}
    }
  } else if($ongoing($b)){return 1;}
  if($a['start_date'] != $b['start_date']){
    return strnatcmp($a['start_date'],$b['start_date']);
  } else {
    return strnatcmp($a['end_date'],$b['end_date']);
  }
});

print_r($events);

【讨论】:

  • 谢谢彼得,有道理 - 没想到只是逐个应用每个排序。
  • @addlovely 请记住,每次排序都会撤消之前的排序。您是否只想要一个排序器,三个规则按降序应用?
  • @addlovely 我添加了结合所有规则并考虑当前正在进行的事件的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-23
  • 2016-09-30
  • 1970-01-01
  • 1970-01-01
  • 2015-09-28
  • 1970-01-01
  • 2018-02-09
相关资源
最近更新 更多