I'm trying to find a way to sort my array from SimpleXMLElement. I'd like to sort by start time which I can get from event_start_dt. I'd also like to sort by room ID as a separate process. Currently the array is in order by object(SimpleXMLElement) #. Here is the var_dump($array):
object(SimpleXMLElement)#275 (1) {
["reservation"]=> array(3)
{
[0]=> object(SimpleXMLElement)#287 (28) {
["reservation_id"]=> string(7) "8644894"
["event_start_dt"]=> string(25) "2013-12-02T12:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T13:00:00-08:00"
["event_id"]=> string(6) "314147"
["event_name"]=> string(24) "Practice"
["room_id"]=> string(3) "202"
}
[1]=> object(SimpleXMLElement)#288 (28) {
["reservation_id"]=> string(7) "8595185"
["event_start_dt"]=> string(25) "2013-12-02T08:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T09:00:00-08:00"
["event_id"]=> string(6) "314005"
["event_name"]=> string(24) "Meeting"
["room_id"]=> string(3) "207"
}
[2]=> object(SimpleXMLElement)#289 (28) {
["reservation_id"]=> string(7) "8718654"
["event_start_dt"]=> string(25) "2013-12-02T10:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T11:00:00-08:00"
["event_id"]=> string(6) "315811"
["event_name"]=> string(20) "Maintenance"
["room_id"]=> string(3) "202"
}
} }
I've tried usort and asort but haven't gotten it to work with either method.
usort method:
function sortByTime($a, $b){
$a = strtotime($array->event_start_dt);
$b = strtotime($array->event_start_dt);
if ($a==$b) return 0;
return ($a < $b) ?-1 : 1;
}
usort($arrTimes, 'sortByTime');
var_dump($arrTimes);
Trying the code below gives me warning: usort() expects parameter 1 to be array, object given.
foreach ($rez->reservation as $value){
$var1 = $value->space_reservation->space_name;
$var2 = substr($value->event_start_dt,11,5);
}
sort_obj_arr($value,$var1,SORT_DESC);
echo "<pre>SORTED ";
print_r($value);
echo "</pre>";
function sort_obj_arr(& $arr, $sort_field, $sort_direction)
{
$sort_func = function($obj_1, $obj_2) use ($sort_field, &$sort_direction)
{
if ($sort_direction == SORT_ASC) {
return strnatcasecmp($obj_1->$sort_field, $obj_2->$sort_field);
} else {
return strnatcasecmp($obj_2->$sort_field, $obj_1->$sort_field);
}
};
usort($arr, $sort_func);
}
I have an array from my controler but cannot get usort working:
I get either: usort() expects parameter 1 to be array, object given or null.
$array = array($this->data);
print_r($array);
array(1) {
[0]=> object(SimpleXMLElement)#280 (1) { ["reservation"]=> array(3) {
[0]=> object(SimpleXMLElement)#287 (28) {
["reservation_id"]=> string(7) "8644894"
["event_start_dt"]=> string(25) "2013-12-02T12:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T13:00:00-08:00"
["event_id"]=> string(6) "314147"
["event_name"]=> string(24) "Practice"
["room_id"]=> string(3) "202"
}
[1]=> object(SimpleXMLElement)#288 (28) {
["reservation_id"]=> string(7) "8595185"
["event_start_dt"]=> string(25) "2013-12-02T08:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T09:00:00-08:00"
["event_id"]=> string(6) "314005"
["event_name"]=> string(24) "Meeting"
["room_id"]=> string(3) "207"
}
[2]=> object(SimpleXMLElement)#289 (28) {
["reservation_id"]=> string(7) "8718654"
["event_start_dt"]=> string(25) "2013-12-02T10:00:00-08:00"
["event_end_dt"]=> string(25) "2013-12-02T11:00:00-08:00"
["event_id"]=> string(6) "315811"
["event_name"]=> string(20) "Maintenance"
["room_id"]=> string(3) "202"
}
} }
Request for print_r:
SimpleXMLElement Object
(
[reservation] => Array(3)
(
[0] => SimpleXMLElement Object
(
[reservation_id] => 8604174
[event_start_dt] => 2013-12-31T06:00:00-08:00
[event_end_dt] => 2013-12-31T08:00:00-08:00
[event_id] => 314147
[event_name] => Practice
[room_id] => 202
)
[1] => SimpleXMLElement Object
(
[reservation_id] => 8604177
[event_start_dt] => 2013-12-31T05:00:00-08:00
[event_end_dt] => 2013-12-31T06:00:00-08:00
[event_id] => 314150
[event_name] => Meeting
[room_id] => 216
)
[2] => SimpleXMLElement Object
(
[reservation_id] => 8604189
[event_start_dt] => 2013-12-31T10:00:00-08:00
[event_end_dt] => 2013-12-31T11:00:00-08:00
[event_id] => 314150
[event_name] => Maintenance
[room_id] => 220
)
)
)
$arrTimes = xml2array($array->reservation);
var_dump($arrTimes)
array(5) {
["reservation_id"]=> string(7) "8604175"
["event_start_dt"]=> string(25) "2014-01-02T06:00:00-08:00"
["event_end_dt"]=> string(25) "2014-01-02T08:00:00-08:00"
["event_id"]=> string(6) "314147"
["event_name"]=> string(24) "Practice"
}
Use array_multisort
foreach ($rez->reservation as $value)
{
$dateTime[] = $value->event_start_dt;
}
array_multisort($dateTime,SORT_ASC,SORT_STRING,$rez->reservation);
echo "<pre>";
print_r($rez->reservation);
Check it. this is my code
<?php
$myarray=array(
0 => array
(
'dateTime' => '2013-12-02T10:00:00-08:00',
'chanl1' => '20.10',
'chanl2' => '45.4',
'chanl3' => '',
),
1 => array
(
'dateTime' => '2013-12-02T11:00:00-08:00',
'chanl1' => '20.11',
'chanl2' => '45.4',
'chanl3' => '',
),
2 => array
(
'dateTime' => '2013-12-02T12:00:00-08:00',
'chanl1' => '20.12',
'chanl2' => '33.8',
'chanl3' => '',
),
3 => array
(
'dateTime' => '2013-12-02T09:00:00-08:00',
'chanl1' => '20.9',
'chanl2' => '33.9',
'chanl3' => ''
));
foreach($myarray as $c=>$key) {
$dateTime[] = $key['dateTime'];
}
array_multisort($dateTime,SORT_ASC,SORT_STRING,$myarray);
echo "<pre>";
print_r($myarray);
?>
Output is :
Array
(
[0] => Array
(
[dateTime] => 2013-12-02T09:00:00-08:00
[chanl1] => 20.9
[chanl2] => 33.9
[chanl3] =>
)
[1] => Array
(
[dateTime] => 2013-12-02T10:00:00-08:00
[chanl1] => 20.10
[chanl2] => 45.4
[chanl3] =>
)
[2] => Array
(
[dateTime] => 2013-12-02T11:00:00-08:00
[chanl1] => 20.11
[chanl2] => 45.4
[chanl3] =>
)
[3] => Array
(
[dateTime] => 2013-12-02T12:00:00-08:00
[chanl1] => 20.12
[chanl2] => 33.8
[chanl3] =>
)
)
FIDDLE
Before you can sort the data, you need to create an array which contains as its values the separate items you want to sort. From your debug outputs, these are multiple <reservation> nodes in the input XML, which are children of the element represented by $array/$this->data in those samples (it doesn't matter if it's the root of the document or not, SimpleXML has no Document object).
Your print_r and var_dump output shows that you do not currently have such an array, only a SimpleXML object:
Your first example shows var_dump($array) giving output beginning object(SimpleXMLElement)#275 (1) { - ignore the word array further in, that's just how var_dump is rendering the insides of the object.
Later, you have a print_r($array); beginning array(1) { - but this is only because you've wrapped the real data in a single-element array on the line above ($array = array($this->data);) and that one element ($array[0]) shows as object(SimpleXMLElement)#280 (1) { ....
Note that there's no need to go further and convert all the inner SimpleXML objects into arrays - you just need a list that is sortable, containing the items you are interested in. I would personally use a simple and explicit foreach loop, for maximum code readability, although "cleverer" solutions are available.
Once you have a sortable list, you need a callback function for usort which compares its two parameters. The attempt you've made is along the right lines, but refers to the non-existent (in that function) variable $array; the values you need to compare are the function's arguments, which you've called $a and $b - specifically, you want to compare strtotime($a->event_start_dt) with strtotime($b->event_start_dt).
You can also make the function much simpler, because it follows the common misconception that the return value of the callback should be -1, 0, or 1. In fact, it can be any integer, and only its sign matters - returning -42 will have the same effect as returning -999, namely placing item $a before $b in the resulting array.
I can't easily give a tested example, because you haven't provided the underlying XML to reproduce your input (e.g. echo $this->data->asXML();), but the basic approach I would take would be this:
// Start with an empty array, and add all the items we're interested in to it
$sortable_array = array();
// Loop over all <reservation> children of the SimpleXML object $this->data
// See http://php.net/manual/en/simplexml.examples-basic.php
foreach ( $this->data->reservation as $reservation_node )
{
// Add the individual node to our array
$sortable_array[] = $reservation_node;
}
// Now let's sort out the callback function for the sorting
// This could also be an anonymous function passed directly to usort
function sort_callback_event_start($a, $b)
{
// $a and $b are both items in our $sortable_array, and therefore
// <reservation> nodes which we expect to each have a child
// called <event_start_dt>
// If we convert both dates to Unix timestamps, we have two integers
// to compare, and a simple subtraction gives the desired result
// of <0, 0, or >0 as documented at http://php.net/usort
return
strtotime((string)$a->event_start_dt)
-
strtotime((string)$b->event_start_dt);
}
// Now, we have everything we need to do the actual sorting
usort($sortable_array, 'sort_callback_event_start');
// $sortable_array is now sorted as desired! :D
// Note that the items within it are still SimpleXML objects,
// so you still need to access their properties to do something useful
// e.g. some HTML output with the names listed in order of their start date:
echo '<ol>';
foreach ( $sortable_array as $reservation_node )
{
echo '<li>', (string)$reservation_node->event_name, '</li>';
}
echo '</ol>';
I would just cast it as an array using this function (example function from php.net). But note that this will not sort the XML, rather sort the new array
/**
* function xml2array
*
* This function is part of the PHP manual.
*
* The PHP manual text and comments are covered by the Creative Commons
* Attribution 3.0 License, copyright (c) the PHP Documentation Group
*
* #author k dot antczak at livedata dot pl
* #date 2011-04-22 06:08 UTC
* #link http://www.php.net/manual/en/ref.simplexml.php#103617
* #license http://www.php.net/license/index.php#doc-lic
* #license http://creativecommons.org/licenses/by/3.0/
* #license CC-BY-3.0 <http://spdx.org/licenses/CC-BY-3.0>
*/
function xml2array ( $xmlObject, $out = array () )
{
foreach ( (array) $xmlObject as $index => $node )
$out[$index] = ( is_object ( $node ) ) ? xml2array ( $node ) : $node;
return $out;
}
and pass it the XMLObject
$arrTimes = xml2array(YourSimpleXMLElement);
and then use your original usort function on the new array
function sortByTime($a, $b){
$a = strtotime($a['event_start_dt']);
$b = strtotime($b['event_start_dt']);
if ($a==$b)
return 0;
return ($a < $b) ? -1 : 1;
}
Finally
usort($arrTimes, 'sortByTime');
You have to convert frist in to xml to array using json encode decode
$xml_array = json_decode(json_encode((array)$xml), TRUE);
u will get list of array....than u can sory according to date using strtotime function.
Related
I have a very big array, I will try to explain the issue in small examples:
Input:
Array (
[alert:accountDisabled:heading] => XYZ
[alert:accountDisabled:message] => XYZ
[alert:accountExpired:heading] => XYZ
[alert:accountExpired:message] => XYZ
[alert:errorResponse:heading] => XYZ
[button:back] => XYZ
)
What I need to get is:
array() {
["alert"]=> array(7) {
["accountDisabled"]=> array(2) {
["heading"]=> string(3) "XYZ"
["message"]=> string(3) "XYZ" }
["accountExpired"]=> array(2) {
["heading"]=> string(3) "XYZ"
["message"]=> string(3) "XYZ" }
["clientError"]=> array(2) {
["heading"]=> string(3) "XYZ"
["message"]=> string(3) "XYZ" }
["errorResponse"]=> array(1) {
["heading"]=> string(3) "XYZ" }
}
["button"]=> array(1) {
["back"]=> string(3) "XYZ"
}
As I said this is a very small example, but the point is to get hierarchy from keys from array number one, hierarchy is divided by this character in key :
I checked for those questions that look similar to this one but they are not helpful lat all
How to access and manipulate multi-dimensional array by key names / path?
Using a string path to set nested array data
SO please read carefully the description of my issue.
I tried to use it for each loop, and I succeed to divide elements from the key, for one element, but I'm not sure where I need to store those hierarchy values for the next elements, any ideas?
$input = [
'alert:accountDisabled:heading' => 'XYZ_1',
'alert:accountDisabled:message' => 'XYZ_2',
'alert:accountExpired:heading' => 'XYZ_3',
'alert:accountExpired:message' => 'XYZ_4',
'alert:errorResponse:heading' => 'XYZ_5',
'button:back' => 'XYZ_6'
];
$results = [];
foreach ($input as $key => $value) {
$arr = explode(':', $key);
$result = $value;
for ($i = count($arr) - 1; $i >= 0; $i--) {
$result = [ $arr[$i] => $result ];
}
$results[] = $result;
}
$result = array_merge_recursive(...$results);
print_r($result);
Output:
Array
(
[alert] => Array
(
[accountDisabled] => Array
(
[heading] => XYZ_1
[message] => XYZ_2
)
[accountExpired] => Array
(
[heading] => XYZ_3
[message] => XYZ_4
)
[errorResponse] => Array
(
[heading] => XYZ_5
)
)
[button] => Array
(
[back] => XYZ_6
)
)
Based on Lukas.j answer, you can use this function:
function parsePath($array, $separator = ':'){
$result = [];
foreach($array as $key => $value){
if(strpos($key, $separator) !== FALSE){
$keys = explode($separator, $key);
$inner_result = $value;
foreach (array_reverse($keys) as $valueAsKey) $inner_result = [$valueAsKey => $inner_result];
$result[] = $inner_result;
}
}
return array_merge_recursive(...$result);
}
I have an array stored in a variable $data. The array has names in the first row and a value in the second row. The array is very big so I need a way to take the five highest values from it and the name from those value. For example I have this array:
[0]=>
array(1447) {
[1]=>
array(3) {
[0]=>
string(11) "Cris"
[2]=>
string(1) "11"
}
[2]=>
array(3) {
[0]=>
string(7) "Alan"
[2]=>
string(1) "28"
}
[3]=>
array(3) {
[0]=>
string(6) "Alex"
[2]=>
string(1) "50"
}
[4]=>
array(3) {
[0]=>
string(6) "Zone"
[1]=>
string(1) "22"
}
[5]=>
array(3) {
[0]=>
string(6) "Ana"
[2]=>
string(1) "1"
}
[6]=>
array(3) {
[0]=>
string(6) "Fisca"
[1]=>
string(1) "5"
}
In this case I should display: Alex 50, Alan 28, Zone 22, Cris 11 and Fisca 5. I tried to find a solution but I don't know how should I make a top of array values. Can you help me please? Thank you in advance.
First sort your array and then slice the top 5:
DEMO
usort($data, function ($a, $b) {
return $b[1] - $a[1];
}); //Sort your array
$resultant = array_slice($data,0,5); //Pick top 5
Note: If your index used for comparison differs, then change your return statement to:
return (isset($b[1])?$b[1]:$b[2]) - (isset($a[1])?$a[1]:$a[2]);
Example:
<?php
$data = [
['Cris', 11],
['Alan', 28],
['Alex', 50],
['Zone', 22],
['Ana', 1]
];
usort($data, function ($a, $b) {
return $b[1] - $a[1];
});
print_r(array_slice($data,0,5));
Result:
Array
(
[0] => Array
(
[0] => Alex
[1] => 50
)
[1] => Array
(
[0] => Alan
[1] => 28
)
[2] => Array
(
[0] => Zone
[1] => 22
)
[3] => Array
(
[0] => Cris
[1] => 11
)
[4] => Array
(
[0] => Ana
[1] => 1
)
)
DEMO
You can use this to get the 5 highest values of your array:
<?php
function compare($a, $b) {
if ($a[1] == $b[1]) {
return 0;
}
return ($a[1] > $b[1]) ? -1 : 1;
}
usort($theBigArray, "compare");
$fiveHighestValues = array_slice($theBigArray, 0, 5);
?>
($theBigArray being your array)
And then, you can loop through the $fiveHighestValues var to display the five elements as you want, e.g.:
<?php
foreach($fiveHighestValues as $value) {
echo $value[0] .' has the value '. $value[1];
// output: Alex has the value 50
}
?>
I would first sort the array like this
function mySort($a, $b) {
return $b[1] - $a[1];
}
usort($arr, 'mySort');
Then you can just pop the first 5 values - they are the highest.
You've written that 'The array has names in the first row and a value in the second row.', but I can see that for 'Zone' the index '1' is set not '2', so in your sorting function you might need to add some simple checking, maybe something like this:
function mySortWithCheck($a, $b) {
if (isset($b[1])) {
$valB = $b[1];
} else {
$valB = $b[2];
}
if (isset($a[1])) {
$valA = $a[1];
} else {
$valA = $a[2];
}
return $valB - $valA;
}
<?php
$data = array(
array("Cris", "11"),
array("Alan", "28"),
array("Alex","50"),
array("Zone","22"),
array("Ana","1")
);
var_dump($data);
function custom_array_sort($a, $b) {
return $b[1] - $a[1];
}
usort($data,'custom_array_sort');
$sorted = array_slice($data,0,5);
var_dump($sorted);
?>
I have an array which I got from a directory with pdf files in it using scandir
$array = array(7) {
[0]=> string(17) "q150824-spost.pdf"
[1]=> string(17) "s150826-spost.pdf"
[2]=> string(16) "s150826-spro.pdf"
[3]=> string(17) "t150827-spost.pdf"
[4]=> string(16) "t150827-spro.pdf"
[5]=> string(17) "v150825-spost.pdf"
[6]=> string(16) "v150825-spro.pdf"
}
I need to sort the array by the numbers in the file name (eg. 150824 which is actually a date) which I can do using the following:
usort($array, function($a, $b) {
return filter_var($a, FILTER_SANITIZE_NUMBER_INT) - filter_var($b, FILTER_SANITIZE_NUMBER_INT);
});
The above gives me an array sorted by the numbers (which is almost what I want):
$array = array(7) {
[0]=> string(17) "q150824-spost.pdf"
[1]=> string(17) "v150825-spost.pdf"
[2]=> string(16) "v150825-spro.pdf"
[3]=> string(16) "s150826-spro.pdf"
[4]=> string(17) "s150826-spost.pdf"
[5]=> string(17) "t150827-spost.pdf"
[6]=> string(16) "t150827-spro.pdf"
}
However, in addition to this I would also like to sort alphabetically by spost and spro (the text before .pdf) I'm at a loss as to how to achieve this though?
If two strings in the array have the same numbers/date (eg. 150826) I want to then sort by spost first and then spro.
This should work for you:
First just grab the number and the topic name out of the file name with preg_match_all() and assign it to the variables. After this simply sort it by the topic, if the numbers are equal, otherwise by the numbers.
<?php
usort($arr, function($a, $b){
preg_match_all("/^\w(\d+)-(\w+)/", $a, $mA);
preg_match_all("/^\w(\d+)-(\w+)/", $b, $mB);
$numberA = $mA[1][0];
$numberB = $mB[1][0];
$topicA = $mA[2][0];
$topicB = $mB[2][0];
if($numberA == $numberB){
return strcmp($topicA, $topicB);
}
return $numberA > $numberB ? 1 : -1;
});
print_r($arr);
?>
output:
Array
(
[0] => q150824-spost.pdf
[1] => v150825-spost.pdf
[2] => v150825-spro.pdf
[3] => s150826-spost.pdf
[4] => s150826-spro.pdf
[5] => t150827-spost.pdf
[6] => t150827-spro.pdf
)
Actually you can just do the following
$array =[
"q150824-spost.pdf",
"s150826-spost.pdf",
"s150826-spro.pdf",
"t150827-spost.pdf",
"t150827-spro.pdf",
"v150825-spost.pdf",
"v150825-spro.pdf",
];
usort($array, function($a, $b) {
return filter_var($a, FILTER_SANITIZE_NUMBER_INT) - filter_var($b, FILTER_SANITIZE_NUMBER_INT) + (strlen($b) > strlen($a) ? 1 : 0);
});
print_r($array);
Output
Array
(
[0] => q150824-spost.pdf
[1] => v150825-spost.pdf
[2] => v150825-spro.pdf
[3] => s150826-spost.pdf
[4] => s150826-spro.pdf
[5] => t150827-spost.pdf
[6] => t150827-spro.pdf
)
It is sort by spost first and then spro
Let's say I have this array:
array(12) {
[0] =>
array(0) {
}
// [...]
[9] =>
string(5) "test"
[10] =>
array(0) {
}
[11] =>
class stdClass#5 (0) {
}
}
All items in this array where added like this $a[] = $somevalue.
Now I add another item: $a[] = new Foobar('bar');
However this results in:
array(13) {
[0] =>
array(0) {
}
// [...]
[9] =>
string(5) "test"
[10] =>
array(0) {
}
[11] =>
class stdClass#5 (0) {
}
[21] =>
class Foobar#8 (3) {
protected $id =>
string(11) "bar"
}
}
My Foobar object is not $a[12], why? Is there anything I can do such that PHP iterates properly?
Update:
I was not able to reproduce this behaviour in a single file. Unfortunately, a whole framework is involved in my code. As I'm only in control of the last statement ($a[] = new Foobar('id');), can I do something before that expression to force PHP to iterate properly?
I'm not sure if you mean this, but here it goes: PHP arrays do not have to be indexed in the standard way; If you unset 12-20, the last item (namely 21 will not have its index changed). You can also have strings as keys; it's more like a key-value pair than a standard table you might find in other languages. You can use foreach to iterate over an array.
$a = array(
0 => 2,
21 => 30,
"foo" => "bar"
);
foreach ($a as $val)
{
echo $val;
echo "\n";
}
will print:
2
30
bar
I have a xml parser that returns an associative array. Here's the structure:
<addresses id="123">
<anonymous-address> <test>data 1 </test>
</anonymous-address>
</addresses>
print_r($this->params) will return
Array
(
[addresses] => Array
(
[id] => 123
[anonymous-address] => Array
(
[0] => Array
(
[test] => Array
(
[VALUE] => data 1
)))))
This array then gets passed through list() as:
list($root, $data) = $parsedXML;
Then I attempt to get an id attribute from root and read to do it this way:
$id = $data[$root]['id'];
Edit: This works for all but one $root value which it 400's for. This case of the switch ($root) has the same code as the others, so I have no idea why it errs only there.
var_dump($root, $data) outputs
string (9) "addresses"
array(1) {
["addresses"]=>
array(2) {
["id"]=>
string(3) "123"
["anonymous-address"]=>
array(1) {
["VALUE"]=>
string(7) "data 1 "
}
}
}
$a = list($root, $data);
now $a will be:
array(0 => $root, 1 => $data);
so you can get them like this:
$a[0], $a[1]
so probably
$id = $a[1][$a[0]]['id'];