Я имею дело с конкретным запросом от моих пользователей, что я не могу «сломаться».
Ситуация:
мы работаем с историческими данными, которые иногда имеют неизвестные значения даты. Мы, например, знаем, что что-то произошло в 1943 году, но мы не знаем, когда именно, в какой день и в какой месяц. Иногда у нас есть точные даты. Мы работаем с датами от-до, и обычно они связаны друг с другом, поэтому, когда одно событие заканчивается, другое начинается. Вы можете думать об этих событиях, например, как о датах, когда корабль находился в море и в гавани.
Пример:
у нас есть две записи (в этом примере, на самом деле мы можем иметь десятки записей в одном посте), с такой структурой
Date From - Date To - Event
01.01.1943 - 01.02.1943 - Event 1
DD.MM.1943 - 01.04.1943 - Event 2
01.04.1943 - DD.11.1943 - Event 3
DD.02.1943 - 28.02.1943 - Event 4
ДД и ММ остаются для «день неизвестен» и «месяц неизвестен», поэтому формат даты остается в формате ДД.ММ.ГГГГ для дальнейшей обработки.
Проблема:
человеческий глаз и мозг могут быстро разобраться, что есть два связанных события — одно за другим, поскольку оно видит «дату до» в событии 2 равным «дате от» в событии 3, и отсортировать их в правильном порядок. Но когда я хочу сделать это в коде, я использую некоторую функцию php array_sort (и сортирую ее только по dateFrom, например), я получу этот ПЛОХОЙ порядок
Date From - Date To - Event
01.01.1943 - 01.02.1943 - Event 1
01.04.1943 - DD.11.1943 - Event 3
DD.02.1943 - 28.02.1943 - Event 4
DD.MM.1943 - 01.04.1943 - Event 2
из-за порядка «01» в алфавите, предшествующем строке «DD». Ожидаемый ПРАВИЛЬНЫЙ заказ
Date From - Date To - Event
01.01.1943 - 01.02.1943 - Event 1
DD.02.1943 - 28.02.1943 - Event 4
DD.MM.1943 - 01.04.1943 - Event 2
01.04.1943 - DD.11.1943 - Event 3
Есть ли способ, как заказать это так же, как человеческий мозг? Я, честно говоря, понятия не имею, как к этому подойти.
Спасибо
Прежде всего, для сортировки лучше сохранить свою дату внутри YYYY-MM-DD, поэтому 1943-04-01 ниже, чем 1943-11-DD.
Может быть, вы можете использовать скрытое свойство для сортировки.
Во-вторых, не ясно, что делать с вашими неизвестными данными, но вы можете установить все неизвестные даты на ноль, но я думаю, что это не то, что вы хотите
Так например
Event 1 :DD.MM.1943 - 01.04.1943
Event 2 :01.04.1943 - DD.11.1943
Event 3 :DD.MM.1943 - DD.12.1943
Я думаю, что вы можете использовать поле даты сортировки, которое не является точным, но поможет вам в сортировке
Если дата от почти известна, то дата сортировки — это дата от.
Если есть неизвестные детали, но дата известна, то дата сортировки будет датой — 1 день
Я думаю, что вам нужно больше ролей, и некоторые части могут не всегда быть правильными, но могут помочь вам
Вторая попытка Это обеспечивает желаемый результат, используя ваши новые входные данные.
Метод: (демонстрация)
$post='Date From - Date To - Event
01.01.1943 - 01.02.1943 - Event 1
01.04.1943 - DD.11.1943 - Event 3
DD.02.1943 - 28.02.1943 - Event 4
DD.MM.1943 - 01.04.1943 - Event 2';
$rows=array_slice(explode("\r\n",$post),1); // split by linebreak, remove column heading row
preg_match_all('/- ([\dD]{2}).([\dM]{2}).([\dY]{4})/',$post,$to_bits,PREG_SET_ORDER); // extract Date To values
foreach($to_bits as $i=>$a){
$keyed_rows["{$a[3]}-{$a[2]}-{$a[1]}"]=$rows[$i]; // assign Date To values as keys
}
ksort($keyed_rows); // sort by keys ASC
echo "Date From - Date To - Event\n",implode("\n",$keyed_rows);
Выход:
Date From - Date To - Event
01.01.1943 - 01.02.1943 - Event 1
DD.02.1943 - 28.02.1943 - Event 4
DD.MM.1943 - 01.04.1943 - Event 2
01.04.1943 - DD.11.1943 - Event 3
Если это не соответствует тому, что вы намереваетесь с вашими фактическими данными проекта, пожалуйста, улучшите ваш вопрос с помощью примера ввода, который выявит ошибку в моем методе.
@Radek, у меня есть немного доработать свою идею, и вот как алгоритм в качестве отправной точки. Может быть, это требует доработки, но вы можете проверить это с вашими данными …
<?php
$event[0]['from']='1943-00-00';
$event[0]['to']='1943-04-00';
$event[1]['from']='1943-05-00';
$event[1]['to']='1943-05-14';
$event[2]['from']='1943-06-00';
$event[2]['to']='1943-06-20';
$event[3]['from']='1943-06-00';
$event[3]['to']='1943-06-00';
$event[4]['from']='1943-04-00';
$event[4]['to']='1943-05-13';
$event[5]['from']='1943-05-14';
$event[5]['to']='1943-00-00';
print_r($event);
$dates=array();
foreach($event as $key => $value)
{
$from['date']=$value['from'];
$from['type']=1;
$from['id']=$key;
array_push($dates,$from);
$to['date']=$value['to'];
$to['type']=2;
$to['id']=$key;
array_push($dates,$to);
}
function compare_dates($a, $b)
{
// sort by date
$retval = strcmp($a['date'], $b['date']);
// if date are equal sort my id
if(!$retval) $retval = $a['id'] - $b['id'];
//if also id is equal sort by type
if(!$retval) $retval = $a['type'] - $b['type'];
return $retval;
}//first sort by date
usort($dates,'compare_dates');
/*
* unspezific dates shoud be more at the beginning than specific dates
* So go from back to begin
*/
function searchEvent($array,$id)
{
$result=false;
foreach( $array as $key => $value)
{
if($value['id'] == $id)
{
$result=$key;
break;
}
}
return $result;
}
print_r($dates);
$newEvent=array();
//go over dates and rebuild events
while(count($dates) > 0 )
{
//on the beginn of array we hve the most unspezific events, so we start on the end
$lastdate=array_pop($dates);
$id=$lastdate['id'];
$type=$lastdate['type'];
if($type == 1)
{
$from=$lastdate['date'];
}
else
{
$to=$lastdate['date'];
}
$otherDateKey=searchEvent($dates, $id);
$otherDate=$dates[$otherDateKey];
array_splice($dates, $otherDateKey,1);
$type=$otherDate['type'];
if($type == 1)
{
$from=$otherDate['date'];
}
else
{
$to=$otherDate['date'];
}
$data['from']=$from;
$data['to']=$to;
array_unshift($newEvent, $data);
}
print_r($newEvent);
?>