Сортировка 5-мерного массива по дате в 5-м измерении с использованием php?
Мне нужно отсортировать массив с использованием дат, но проблема в том, что первый массив сохраняет это значение в ключе added_date
, а второй использует ключ date_added
.
Как я могу отсортировать их по дате (более новые элементы)?
Массив имеет следующую структуру:
[0] => Array
(
[data] => Array
(
[0] => Array
(
[media] => upcomingEvents_1214_1429325758.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:00
[type] => image/jpeg
)
[1] => Array
(
[media] => upcomingEvents_1214_1429325809.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:51
[type] => image/jpeg
)
[2] => Array
(
[media] => diary_1214_1434190391.jpeg
[reference] => diary
[added_date] => 2015-06-13 15:43:11
[type] => image/jpeg
)
)
[identifier] => media
)
[1] => Array
(
[data] => Array
(
[0] => Array
(
[media] => image.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 08:38:09
[chat_type] => image/jpeg
)
[1] => Array
(
[media] => 1432787219556.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 17:45:45
[chat_type] => image/jpeg
)
[2] => Array
(
[media] => 1436160762565.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-07-06 09:03:27
[chat_type] => image/jpeg
)
)
[identifier] => chat
)
Ответы
Ответ 1
Поскольку OP ничего не говорит о структуре массива вывода, я предполагаю, что он должен быть таким же, как структура ввода. Далее я думаю, что все записи должны сортироваться по дате независимо от их типа (чат или медиа).
Следующий алгоритм выполняет три шага:
- Deflate массив в двумерный массив
- Сортировка дефлированного массива
- Нажать отсортированный массив
Благодарим вас, что мы можем смешивать типы и сортировать их, не теряя структуру.
Код
// Deflate array
function deflate($arr)
{
$deflated = array();
foreach($arr as $dataGroup) {
foreach ($dataGroup['data'] as $item) {
$item['identifier'] = $dataGroup['identifier'];
$deflated[] = $item;
}
}
return $deflated;
}
// Inflate array
function inflate($arr)
{
$inflated = array();
$lastIdentifier = NULL;
foreach ($arr as $item) {
if ($item['identifier'] != $lastIdentifier) {
if (isset($dataGroup)) {
$dataGroup['identifier'] = $lastIdentifier;
}
unset($dataGroup);
$dataGroup = array();
$inflated[] = &$dataGroup;
}
$lastIdentifier = $item['identifier'];
unset($item['identifier']);
$dataGroup['data'][] = $item;
}
if (isset($dataGroup)) {
$dataGroup['identifier'] = $lastIdentifier;
}
return $inflated;
}
// Sort deflated array by date
function sortArray(&$arr)
{
$callback = function($a, $b)
{
if(isset($a['added_date'])) {
$aDate = $a['added_date'];
} elseif(isset($a['date_added'])) {
$aDate = $a['date_added'];
} else {
$aDate = '';
}
if(isset($b['added_date'])) {
$bDate = $b['added_date'];
} elseif(isset($b['date_added'])) {
$bDate = $b['date_added'];
} else {
$bDate = '';
}
return ($aDate < $bDate) ? 1 : -1;
};
usort($arr, $callback);
}
// Test output
print_r($arr);
// 1. step: deflate array
$arr = deflate($arr);
// echo "--- deflated ---\n";
// print_r($arr);
// 2. step: sort deflated array
sortArray($arr);
// echo "--- deflated and sorted ---\n";
// print_r($arr);
// 3. step: inflate sorted array
$arr = inflate($arr);
echo "--- sorted and inflated ---\n";
print_r($arr);
Вы можете прокомментировать строки печати, чтобы увидеть плоский массив до и после сортировки.
Вывод теста
Array
(
[0] => Array
(
[data] => Array
(
[0] => Array
(
[media] => upcomingEvents_1214_1429325758.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:00
[type] => image/jpeg
)
[1] => Array
(
[media] => upcomingEvents_1214_1429325809.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:51
[type] => image/jpeg
)
[2] => Array
(
[media] => diary_1214_1434190391.jpeg
[reference] => diary
[added_date] => 2015-06-13 15:43:11
[type] => image/jpeg
)
)
[identifier] => media
)
[1] => Array
(
[data] => Array
(
[0] => Array
(
[media] => image.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 08:38:09
[chat_type] => image/jpeg
)
[1] => Array
(
[media] => 1432787219556.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 17:45:45
[chat_type] => image/jpeg
)
[2] => Array
(
[media] => 1436160762565.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-07-06 09:03:27
[chat_type] => image/jpeg
)
)
[identifier] => chat
)
)
--- sorted and inflated ---
Array
(
[0] => Array
(
[data] => Array
(
[0] => Array
(
[media] => 1436160762565.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-07-06 09:03:27
[chat_type] => image/jpeg
)
[1] => Array
(
[media] => 1432787219556.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 17:45:45
[chat_type] => image/jpeg
)
[2] => Array
(
[media] => image.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 08:38:09
[chat_type] => image/jpeg
)
)
[identifier] => chat
)
[1] => Array
(
[data] => Array
(
[0] => Array
(
[media] => diary_1214_1434190391.jpeg
[reference] => diary
[added_date] => 2015-06-13 15:43:11
[type] => image/jpeg
)
[1] => Array
(
[media] => upcomingEvents_1214_1429325809.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:51
[type] => image/jpeg
)
[2] => Array
(
[media] => upcomingEvents_1214_1429325758.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:00
[type] => image/jpeg
)
)
[identifier] => media
)
)
С используемым массивом кажется, что нет большой разницы в решении, которое только сортирует внутренний массив. Но будет разница, если у вас есть даты, которые смешивают типы. Например, элемент мультимедиа, который является новее, чем элемент чата, и другой элемент мультимедиа, который старше. На показанном выходе все элементы мультимедиа старше, чем элементы чата.
Благодаря AVGP и приятным. Они вдохновили меня на мое решение с их ответами: плоское решение AVGP и затратная сортировка внутренних массивов.
Ответ 2
В общем, вы должны сначала сгладить массив, чтобы упростить сортировку.
Как только вы получите размерность до разумного плоского массива массивов с помощью date_added
или added_date
, вы можете использовать usort
с функцией, которая проверяет существующий ключ двух, а затем сравнивает их.
Здесь немного упрощенная выборка:
<?php
$arr = array(
array(
'data' => array(
array('date_added' => 3),
array('date_added' => 1),
array('date_added' => 6)
)
),
array(
'data' => array(
array('added_date' => 4),
array('added_date' => 0),
array('added_date' => 5)
)
)
);
function normalize($arr_elem) {
return $arr_elem['data'];
}
function sort_by_date($a, $b) {
$dateA = array_key_exists('date_added', $a) ? $a['date_added'] : $a['added_date'];
$dateB = array_key_exists('date_added', $b) ? $b['date_added'] : $b['added_date'];
return $dateA > $dateB;
}
$flattened = array_reduce(array_map('normalize', $arr), 'array_merge', array());
usort($flattened, 'sort_by_date');
var_dump($flattened);
?>
Ответ 3
- Мы создаем функцию, которая принимает массив как аргумент, передаваемый по ссылке.
- Мы перебираем его значения также по ссылке и применяем
usort
к клавише data
для подмассивов.
-
usort
показывает, доступен ли ключ date_added
или added_date
, извлекает значения, преобразует их в dateTime
и сравнивает их, чтобы вернуть порядок сортировки.
Поскольку вы ничего не говорили о слиянии различных массивов data
, это решение сохраняет исходную структуру.
Код
// the function
function sortByDate(&$arr) {
$callback = function($a, $b) {
if(isset($a['added_date'])) {
$key = 'added_date';
}
elseif(isset($a['date_added'])) {
$key = 'date_added';
}
else {
return 0;
}
$d1 = DateTime::createFromFormat('Y-m-d H:i:s', $a[$key]);
$d2 = DateTime::createFromFormat('Y-m-d H:i:s', $b[$key]);
return ($d1 < $d2) ? 1 : -1;
};
foreach($arr as &$subArr) {
usort($subArr['data'], $callback);
}
}
Тест
// the data as JSON, provided for reproducibility
$arr = json_decode('[{"data":[
{"media":"upcomingEvents_1214_1429325758.jpeg","reference":"upcomingEvents","added_date":"2015-04-18 08:26:00","type":"image\/jpeg"},
{"media":"diary_1214_1434190391.jpeg","reference":"diary","added_date":"2015-06-13 15:43:11","type":"image\/jpeg"},
{"media":"upcomingEvents_1214_1429325809.jpeg","reference":"upcomingEvents","added_date":"2015-04-18 08:26:51","type":"image\/jpeg"}
],"identifier":"media"},
{"data":[
{"media":"1432787219556.jpg","media_thumb":"","couple_id":"312","date_added":"2015-06-22 17:45:45","chat_type":"image\/jpeg"},
{"media":"1436160762565.jpg","media_thumb":"","couple_id":"312","date_added":"2015-07-06 09:03:27","chat_type":"image\/jpeg"},
{"media":"image.jpg","media_thumb":"","couple_id":"312","date_added":"2015-06-22 08:38:09","chat_type":"image\/jpeg"}
],"identifier":"chat"}]', true);
// testing
print_r($arr);
sortByDate($arr);
echo "--- sorted ---\n";
print_r($arr);
Выход
Array
(
[0] => Array
(
[data] => Array
(
[0] => Array
(
[media] => upcomingEvents_1214_1429325758.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:00
[type] => image/jpeg
)
[1] => Array
(
[media] => diary_1214_1434190391.jpeg
[reference] => diary
[added_date] => 2015-06-13 15:43:11
[type] => image/jpeg
)
[2] => Array
(
[media] => upcomingEvents_1214_1429325809.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:51
[type] => image/jpeg
)
)
[identifier] => media
)
[1] => Array
(
[data] => Array
(
[0] => Array
(
[media] => 1432787219556.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 17:45:45
[chat_type] => image/jpeg
)
[1] => Array
(
[media] => 1436160762565.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-07-06 09:03:27
[chat_type] => image/jpeg
)
[2] => Array
(
[media] => image.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 08:38:09
[chat_type] => image/jpeg
)
)
[identifier] => chat
)
)
--- sorted ---
Array
(
[0] => Array
(
[data] => Array
(
[0] => Array
(
[media] => diary_1214_1434190391.jpeg
[reference] => diary
[added_date] => 2015-06-13 15:43:11
[type] => image/jpeg
)
[1] => Array
(
[media] => upcomingEvents_1214_1429325809.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:51
[type] => image/jpeg
)
[2] => Array
(
[media] => upcomingEvents_1214_1429325758.jpeg
[reference] => upcomingEvents
[added_date] => 2015-04-18 08:26:00
[type] => image/jpeg
)
)
[identifier] => media
)
[1] => Array
(
[data] => Array
(
[0] => Array
(
[media] => 1436160762565.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-07-06 09:03:27
[chat_type] => image/jpeg
)
[1] => Array
(
[media] => 1432787219556.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 17:45:45
[chat_type] => image/jpeg
)
[2] => Array
(
[media] => image.jpg
[media_thumb] =>
[couple_id] => 312
[date_added] => 2015-06-22 08:38:09
[chat_type] => image/jpeg
)
)
[identifier] => chat
)
)
Ответ 4
Лично я предпочитаю OO-подход:)
<?php
date_default_timezone_set('Europe/London');
class ArraySort {
private $unsortedArray = array();
private $sortedArray = array();
private static $dateKeySynonym = array('added_date', 'date_added');
public function __construct($unsortedArray) {
$this->unsortedArray = $unsortedArray;
}
public function doSort() {
$outputArray = array();
foreach ($this->unsortedArray as $cell) {
$identifier = $cell['identifier'];
foreach ($cell['data'] as $subCell) {
// must keep the identifier : don't loose it !!
$subCell['identifier'] = $identifier;
$outputArray[] = $subCell;
}
}
usort($outputArray, array('ArraySort', '_sort'));
$this->sortedArray = $outputArray;
}
public function getSortedArray() {
return $this->sortedArray;
}
private static function _sort($a, $b) {
$date1 = NULL;
$date2 = NULL;
foreach(self::$dateKeySynonym as $dateKeySynonym) {
if (isset($a[$dateKeySynonym])) {
$date1 = new DateTime($a[$dateKeySynonym]);
break;
}
}
foreach(self::$dateKeySynonym as $dateKeySynonym) {
if (isset($b[$dateKeySynonym])) {
$date2 = new DateTime($b[$dateKeySynonym]);
break;
}
}
return ($date1 < $date2);
}
}
// ---------------------- test class ---------------------------
$a[0]['identifier'] = 'media';
$cell['media'] = 'upcomingEvents_1214_1429325758.jpeg';
$cell['reference'] = 'upcomingEvents';
$cell['added_date'] = '2015-04-18 08:26:00';
$cell['type'] = 'image/jpeg';
$a[0]['data'][] = $cell;
$cell['media'] = 'upcomingEvents_1214_1429325809.jpeg';
$cell['reference'] = 'upcomingEvents';
$cell['added_date'] = '2015-04-18 08:25:51';
$cell['type'] = 'image/jpeg';
$a[0]['data'][] = $cell;
$cell['media'] = 'diary_1214_1434190391.jpeg';
$cell['reference'] = 'diary';
$cell['added_date'] = '2015-06-13 15:43:11';
$cell['type'] = 'image/jpeg';
$a[0]['data'][] = $cell;
// -----------------------------------------------------------
unset($cell);
// -----------------------------------------------------------
$a[1]['identifier'] = 'chat';
$cell['media'] = 'image.jpg';
$cell['media_thumb'] = '';
$cell['couple_id'] = 312;
$cell['date_added'] = '2015-06-22 08:38:09';
$cell['chat_type'] = 'image/jpeg';
$a[1]['data'][] = $cell;
$cell['media'] = '1436160762565.jpg';
$cell['media_thumb'] = '';
$cell['couple_id'] = 312;
$cell['date_added'] = '2015-07-06 09:03:27';
$cell['chat_type'] = 'image/jpeg';
$a[1]['data'][] = $cell;
// -------------------------------------------------------------
$arraySort = new ArraySort($a);
$arraySort->doSort();
var_dump($arraySort->getSortedArray());
Ответ 5
Это работает (для меня), но разрушает структуру массива, и вы теряете ключ [identifier].
Я использовал ['id'], чтобы проверить порядок, если я изменил порядок, в котором объект заполнен, выход останется неизменным (Отсортировано: сначала самое новое):
$subject = array(
array( 'data' => array(
array( 'id' => 1 , 'added_date' => '2015-04-18 08:26:00' ) ,
array( 'id' => 2 , 'added_date' => '2015-04-18 08:26:51' ) ,
array( 'id' => 3 , 'added_date' => '2015-06-13 15:43:11' ) ,
) ) ,
array( 'data' => array(
array( 'id' => 4 , 'date_added' => '2015-06-22 08:38:09' ) ,
array( 'id' => 5 , 'date_added' => '2015-06-22 17:45:45' ) ,
array( 'id' => 6 , 'date_added' => '2015-07-06 09:03:27' ) ,
) ) );
$dates = array();
foreach ($subject as $k1=>$d1) {
foreach ($d1['data'] as $k3=>$d3) {
if(isset($d3['date_added'])) array_push($dates, $d3['date_added'].'|'.$k1.'|'.$k3);
if(isset($d3['added_date'])) array_push($dates, $d3['added_date'].'|'.$k1.'|'.$k3);
}
}
rsort($dates, SORT_STRING );
$sorted = array();
foreach ($dates as $val) {
preg_match('/([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9])\|([0-9]+)\|([0-9]+)/',$val, $matches);
array_push($sorted, $subject[$matches[2]]['data'][$matches[3]]);
}
$result= array();
foreach ($sorted as $key => $val) {
$result[(count($sorted)-1)-$key]=$val;
}
print_r($result); // < This prints the array
Если это решение не подходит для вас, прокомментируйте и я попытаюсь настроить.
Ответ 6
Как указывали другие, я не уверен, какой результат вы ожидаете. Массив, приведенный здесь, представляет собой массив элементов мультимедиа, отсортированных по датам. Они находятся в одном формате, только теперь это всего лишь двумерный массив. Он использует сортировку слияния для сортировки элементов массива. Я не тестировал этот код, но этого достаточно для того, что вам нужно. Мы используем класс Splqueue для сортировки элементов:
$searchQueue = new SplQueue(); // we will store our media nodes here
$sortedQueue = new SplQueue(); // we will have our sorted array nodes here
Наша первая функция найдет элементы мультимедиа и поместит их в очередь
function findArrays($someArray) {
foreach ($someArray as $anArray) {
if (array_key_exists("type", $anArray) {
// bottom level array
$searchQueue.enqueue($anArray);
}
else {
$searchQueue.enqueue(sortArrays($anArray));
}
}
}
Эта следующая функция будет гранулировать эти элементы мультимедиа и является рекурсивной. Как только он гранулируется до одной ячейки, функция начинает сортировку через нашу следующую функцию...
function mergeSort($someQueue){
if ($someQueue.count() <= 1 {
return $someQueue;
}
$left = new SplQueue();
$right = new SplQueue();
$middle = (int)$someQueue.count() / 2;
for ($x = 0; $x < $middle; $x++){
$left.queue($someQueue.dequeue());
}
for ($x = 0; $x < $someQueue.count(); $x++){
$right.queue($someQueue.dequeue());
}
$sortedLeft = mergeSort($left);
$sortedRight = mergeSort($right);
return merge($sortedLeft, $sortedRight); // calls the sorting function
}
Последняя функция - это то, что фактически сортирует элементы. Это займет две очереди и сравните их значения.
function merge($left, $right){
$result = new SplQueue();
$dateTimeFormat = "Y-m-d H:i:s";
while (!$left.isEmpty() && !$right.isEmpty()) {
// find what we are going to compare to what (added_date or date_added)
$leftVal;
$rightVal;
if (array_key_exists("added_date", $left.bottom())) {
$leftVal = DateTime::createFromFormat($dateTimeFormat, $left.bottom()["added_date"]);
}
else {
$leftVal = DateTime::createFromFormat($dateTimeFormat, $left.bottom()["date_added"]);
}
if (array_key_exists("added_date", $right.bottom())) {
$rightVal = DateTime::createFromFormat($dateTimeFormat, $right.bottom()["added_date"]);
}
else {
$rightVal = DateTime::createFromFormat($dateTimeFormat, $right.bottom()["date_added"]);
}
// $leftVal and $rightVal now contain the values we are going to compare
if ($leftVal < $rightVal) {
$result.enqueue($left.dequeue());
}
else {
$result.enqueue($right.dequeue());
}
}
while (!$left.isEmpty()) {
$result.enqueue($left.dequeue());
}
while (!$left.isEmpty()) {
$result.enqueue($right.dequeue());
}
return $result;
}
Эти две функции используются вместе с определенными очередями для создания сортированной очереди. Затем очередь помещается в массив.
// bread and butter
findArrays($yourArrays);
$sortedMediaNodes = mergeSort($searchQueue); // sorted media nodes in a queue
$arrayResults = array(); // will contain an array of the $sortedMediaNodes queue
while (!$sortedMediaNodes.isEmpty()) {
$arrayResults[] = $sortedMediaNodes.dequeue();
}
Я не совсем уверен, что это то, что вы хотели, но независимо от того, какие вышеперечисленные функции являются сортировкой слияния и при необходимости при необходимости.