问题
I need to sort an array using dates, but the problem is that the first array stores that value in the key added_date
while the second one uses the key date_added
.
How can I sort them according to date (newer elements first)?
The array has the following structure:
[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:
As the OP does not say anything about the array structur of the output I assume that it should be the same as the input structure. Further I think all entries should be sorted by date independently of their type (chat or media).
The following algorithm takes three steps:
- Deflate the array into a two dimensional array
- Sort the deflated array
- Inflate the sorted array
The advatage of doing so is that we can mix the types and sort them without losing the structure.
Code
// 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);
You can comment in the print lines to see the flat array before and after sorting.
Output of the test
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
)
)
With the used array it seems that there is no big difference to a solution which only sorts the inner array. But there will be a difference, if you have dates which mix the types. For example a media item which is newer than a chat item and another media item which is older. In the shown output all media items are older than the chat items.
Thanks to AVGP and spendious. They inspired me to my solution with their answers: AVGP's flat solution and spendious's sorting of the inner arrays.
回答2:
In general, you should flatten the array first, so you can sort it more easily.
Once you've got the dimensionality down to a reasonable flat array of arrays with either date_added
or added_date
you can use usort
with a function that checks for the existing key of the two and then compares them.
Here's a slightly simplified sample:
<?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:
- We create a function that takes the array as argument, passed by reference.
- We iterate over its values, also by reference, and apply a usort to the
data
key of the subarrays. - The usort looks at whether the key
date_added
oradded_date
is available, fetches the values, converts them todateTime
objects and compares them to return the sorting order.
Since you didn't say anything about merging the various data
arrays, this solution keeps the original structure.
The code
// 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 test
// 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);
The output
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:
Personally, i prefer OO Approach :)
<?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:
This works (for me) but wrecks your array structure and you lose the [identifier] key. I used ['id'] to check the order, if i changed the order in which the subject is filled, the output will stay the same (Sorted: Newest first):
$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
If this solution is not suitable for you, please comment and i will try to adjust.
回答6:
As others have pointed out, I am not sure what output you are expecting. The array given back here is an array of the media elements only sorted by their dates. They are in the same format, only it is now just a two dimensional array. It uses a merge sort to sort the array elements. I did not test this code, but this should suffice as to what you are needing. We are using the Splqueue class to help sort the elements:
$searchQueue = new SplQueue(); // we will store our media nodes here
$sortedQueue = new SplQueue(); // we will have our sorted array nodes here
Our first function will find the media elements and put them into a queue
function findArrays($someArray) {
foreach ($someArray as $anArray) {
if (array_key_exists("type", $anArray) {
// bottom level array
$searchQueue.enqueue($anArray);
}
else {
$searchQueue.enqueue(sortArrays($anArray));
}
}
}
This next function will granulate those media elements and is recursive. Once it has granulated down to a single cell the function begins the sort via our next function...
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
}
The final function is what actually sorts the elements. It will take two queues and compare their values.
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;
}
These two functions are used in conjunction with the defined queues to make a sorted queue. That queue is then ported back into an array.
// 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();
}
I am not quite sure if this is what you wanted, but regardless the above functions are a merge sort and comes in handy when needed.
来源:https://stackoverflow.com/questions/32775857/sorting-a-5-dimensional-array-by-date-in-5th-dimension-value-using-php