Array
array (
[0] => array
(
[field1] => 'name'
[field2] => 'text'
[field3] => array
(
[0] => array
(
[text] => 'This arrays order is to be kept!'
[name] => 'Only sort the sub-sub-array below!'
[order] => ''
)
)
)
[1] => array
(
[field1] => 'name'
[field2] => 'text'
[field3] => array
(
[0] => array
(
[text] => '2014'
[name] => 'Dummy!'
[order] => '1'
)
[1] => array
(
[text] => '2013'
[name] => 'Try me!'
[order] => '2'
)
[2] => array
(
[text] => '1985'
[name] => 'Help!'
[order] => '5'
)
[3] => array
(
[text] => '2002'
[name] => 'Please!'
[order] => '4'
)
[4] => array
(
[text] => '2007'
[name] => 'Order!'
[order] => '3'
)
)
)
...
Goal
I want to keep the 1st and 2nd level array and it's values as is. I need to sort the keys in the 2nd sub-sub-array by the value in theorder-field. So where it says the years, that sub-sub-array should be sorted ASC or DESC. and all other keys/values/structure/map should be kept as is.
Sorted array:
array (
[0] => array
(
[field1] => 'name'
[field2] => 'text'
[field3] => array
(
[0] => array
(
[text] => 'This arrays order is to be kept!'
[name] => 'Only sort the sub-sub-array below!'
[order] => ''
)
)
)
[1] => array
(
[field1] => 'name'
[field2] => 'text'
[field3] => array
(
[0] => array
(
[text] => '2014'
[name] => 'Dummy!'
[order] => '1'
)
[1] => array
(
[text] => '2013'
[name] => 'Try me!'
[order] => '2'
)
[2] => array
(
[text] => '2007'
[name] => 'Order!'
[order] => '3'
)
[3] => array
(
[text] => '2002'
[name] => 'Please!'
[order] => '4'
)
[4] => array
(
[text] => '1985'
[name] => 'Help!'
[order] => '5'
)
)
)
Help
I've spent hours and hours of trying different custom solutions, mostly based on usort() but I've also done it knowing that none of those Q&A were describing the situation I've got.
I'm starting to doubt that it's even possible.
Does anyone know if it is? And if so, can you please shed some light or provide a hint/tutorial/example for demonstration?
Laravel 5.1
I'm retrieving this from a Laravel Model and using toArray();
Is there is a better way to achieve this in Laravel I would be glad to know.
If the sub-subarray you are wanting to sort is always identified by the same key, you can just usort the contents of that key.
foreach ($test as &$value) {
// Using a (^) reference to each value will sort the existing
// array instead of creating a sorted copy.
usort($value['field3'], function($a, $b) {
// You can use an anonymous function like this for the usort comparison function.
if ($a['order'] < $b['order']) return -1;
if ($a['order'] == $b['order']) return 0;
// In case of 'order' ties, you may want to add a comparison of a different key
return 1; // $a['order'] must be > $b['order'] at this point
});
}
Note that the comparison function used in usort:
must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
It may be better to do this using Laravel, because the database will most likely be able to do this sorting faster than PHP will, but we would need to know much more about your model setup to figure that out and that sounds like basically a totally different question.
If I understood the problem correctly, this could be a solution (in these examples $arr is the variable holding the array):
function cmp($a, $b)
{
return ($a['order'] < $b['order']) ? -1 : 1;
}
foreach($arr as $key => $subarr){
foreach($subarr as $key2 => $subsubarr){
if(is_array($subsubarr)){
usort($subsubarr,"cmp");
$subarr[$key2] = $subsubarr;
}
}
$arr[$key] = $subarr;
}
or
function cmp($a, $b)
{
return ($a['order'] < $b['order']) ? -1 : 1;
}
foreach($arr as &$subarr){
foreach($subarr as &$subsubarr){
if(is_array($subsubarr)){
usort($subsubarr,"cmp");
}
}
}
Related
I'm struggling to sort my array of objects into alphabetical order by the title key. Getting error that 'title' is undefined.
I want to go from this:
My Array
(
[0] => Array
(
[area] => TACT
[pages] => Array
(
[0] => Array
(
[id] => 1484
[title] => Registry
)
[1] => Array
(
[id] => 1385
[title] => Education
To:
My Array
(
[0] => Array
(
[area] => TACT
[pages] => Array
(
[0] => Array
(
[id] => 1385
[title] => Education
)
[1] => Array
(
[id] => 1484
[title] => Registry
Have tried:
function sort_alpha_title($a, $b) {
return strnatcmp($a['title'], $b['title']);
}
usort($myArray, 'sort_alpha_title');
You should use
function sort_alpha_title($a, $b) {
return strnatcmp($a['title'], $b['title']);
}
usort($myArray[0]['pages'], 'sort_alpha_title');
Because the title property is a child property of the pages property.
$myArray = array(
array(
'area' => 'TACT',
'pages' => array(
array(
'id' => 1484,
'title' => 'Registry'
),
array(
'id' => 1385,
'title' => 'Education'
)
)
)
);
function sort_alpha_title($a, $b)
{
return strnatcmp($a["title"], $b["title"]);
}
usort($myArray[0]['pages'], 'sort_alpha_title');
var_dump($myArray);
Sry for the doubled answer but i cant add a comment because of my reputation.
tomhuckle wrote
thanks! this works. But only for one of my objects in the array. Sorry the description should of said. ive tried putting a for each loop but that's not working. here's what i tried: foreach($myArray as $a) { usort($a['pages'], 'sort_alpha_title'); }
you dont need the foreach-loop (at the end of your comment) because its already "looped" within one call.
best regards
This question already has answers here:
Possible to pass a closure to usort in PHP?
(2 answers)
How can I sort arrays and data in PHP?
(14 answers)
Closed 2 years ago.
EDIT: I rewrote my post in order to be clearer and provide a standalone case with real values (no Ajax anymore).
I have 2 arrays that are exactly identical except that one has the same values but cleaned (html, special chars, etc..).
I would like to evaluate the sorting against "arrayClean" but to sort "arrayOriginal" instead (not arrayClean) according to that evaluation.
So, this is what I have:
<?php
$arrayOriginal = array(
array('id' => '100','surface' => '<span>300</span>','whatever' => 'qSDqsd'),
array('id' => '5465','surface' => '100 ch','whatever' => 'ghjkghjk'),
array('id' => '40489','surface' => '<b>1000</b>','whatever' => 'fgsdfg')
);
$arrayClean = array(
array('id' => '100','surface' => '300','whatever' => 'qSDqsd'),
array('id' => '5465','surface' => '100','whatever' => 'ghjkghjk'),
array('id' => '40489','surface' => '1000','whatever' => 'fgsdfg')
);
usort($arrayOriginal, function($a, $b) use (&$arrayClean) {
return $a['surface'] < $b['surface'];
});
echo '<pre>'; print_r($arrayOriginal); echo '</pre>';
?>
here is what I get (which is wrong as the arrayClean doesn't seem to be taken into account for the sorting) :
Array
(
[0] => Array
(
[id] => 100
[surface] => <span>300</span>
[whatever] => qSDqsd
)
[1] => Array
(
[id] => 40489
[surface] => <b>1000</b>
[pwhatever] => fgsdfg
)
[2] => Array
(
[id] => 5465
[surface] => 100 ch
[whatever] => ghjkghjk
)
)
But if I use arrayClean alone, just to check if the sorting script is right:
usort($arrayClean, function($a, $b) {
return $a['surface'] < $b['surface'];
});
echo '<pre>'; print_r($arrayClean); echo '</pre>';
Then the result is what I expect it to be:
Array
(
[0] => Array
(
[id] => 40489
[surface] => 1000
[whatever] => fgsdfg
)
[1] => Array
(
[id] => 100
[surface] => 300
[whatever] => qSDqsd
)
[2] => Array
(
[id] => 5465
[surface] => 100
[whatever] => ghjkghjk
)
)
So it seems that evaluating arrayClean but sorting arrayOriginal accordingly doesn't work. It only evaluates AND sort arrayOriginal.
Do I use "use()" wrong ? Should I use something else ?
Thank you.
Assuming both arrays are sorted by a common factor (i.e. id).
uksort($arrayOriginal, function($a, $b) use ($arrayClean) {
return $arrayClean[$a]['surface'] < $arrayClean[$b]['surface'];
});
Emphasising once more, to make it work, both arrays MUST contain elements in the same order. In your case elements of both arrays MUST come in the following order (by id): 100, 5465, 40489
BUT I'd rather do something like:
usort($arrayOriginal, function($a, $b) {
return yourSurfaceCleanMethod($arrayOriginal['surface']) < yourSurfaceCleanMethod($arrayOriginal['surface']);
});
All depends on your needs, of course, but if you are using $arrayClean only as a reference for sorting original array and you have that yourSurfaceCleanMethod handy, I'd definitely do the above.
I think the arrayClean is not needed if your arrayOriginal should be sorted according to the content of the HTML tags.
strip_tags() can be used for this in your sort function.
usort($arrayOriginal, function($a, $b) {
return strip_tags($b['surface']) <=> strip_tags($a['surface']);
});
Note: Use the spaceship operator <=> to get correct comparison results 1, 0 and -1.
I accepted Nemoden's answer as a courtesy because technically it answered the question according to its scope (the test case as presented). But here is the solution I found that works best for me :
$arrayOriginal = array(
array('id' => '100','surface' => '<span>300</span>','whatever' => 'qSDqsd'),
array('id' => '5465','surface' => '100 ch','whatever' => 'ghjkghjk'),
array('id' => '40489','surface' => '<b>1000</b>','whatever' => 'fgsdfg')
);
$arrayClean = array(
array('id' => '100','surface' => '300','whatever' => 'qSDqsd'),
array('id' => '5465','surface' => '100','whatever' => 'ghjkghjk'),
array('id' => '40489','surface' => '1000','whatever' => 'fgsdfg')
);
$surface = array_column($arrayClean, 'Surface');
array_multisort($surface, SORT_DESC, SORT_REGULAR, $arrayOriginal);
And then I get this output, which is EXACTLY what I want:
Array
(
[0] => Array
(
[id] => 40489
[surface] => <b>1000</b>
[whatever] => fgsdfg
)
[1] => Array
(
[id] => 100
[surface] => <span>300</span>
[whatever] => qSDqsd
)
[2] => Array
(
[id] => 5465
[surface] => 100 ch
[whatever] => ghjkghjk
)
)
The answer of Nemoden was very helpful BUT it gave me this, for whatever reason:
Array
(
[1] => Array
(
[id] => 40489
[surface] => <b>1000</b>
[whatever] => fgsdfg
)
[0] => Array
(
[id] => 100
[surface] => <span>300</span>
[whatever] => qSDqsd
)
[2] => Array
(
[id] => 5465
[surface] => 100 ch
[whatever] => ghjkghjk
)
)
The sub arrays are PRINTED in the right order but the sub arrays indexes weren't changed. So when exporting to javascript "arrayOriginal", it would come back to its initial sorting because the sub arrays would be re-ordered according to their indexes again. At least, that's what I experienced.
Anyway, now the problem is solved and the answers I got here were very helpful.
Thank you.
I want to sort associate array in ascending order using sub array key in associate array.
Following is my array.
Array
(
[0] => Array
(
[weight] => 5.6
[item_id] => wQsK0EpTSkAAAAFvOVohK1wK
[item_reference] => M-AAH-960
[tracking_details] => Array
(
[article_id] => G4KZ00002482EXP00007
[consignment_id] => G4KZ00002482
[barcode_id] => G4KZ00002482EXP00007
)
[product_id] => exp
)
[1] => Array
(
[weight] => 19.2
[item_id] => wQsK0EpTSkAAAAFvOVohK1wK
[item_reference] => M-AAH-960
[tracking_details] => Array
(
[article_id] => G4KZ00002482EXP00002
[consignment_id] => G4KZ00002482
[barcode_id] => G4KZ00002482EXP00002
)
[product_id] => exp
)
[2] => Array
(
[weight] => 18.5
[item_id] => wQsK0EpTSkAAAAFvOVohK1wK
[item_reference] => M-AAH-960
[tracking_details] => Array
(
[article_id] => G4KZ00002482EXP00003
[consignment_id] => G4KZ00002482
[barcode_id] => G4KZ00002482EXP00003
)
[product_id] => exp
)
[3] => Array
(
[weight] => 19.3
[item_id] => wQsK0EpTSkAAAAFvOVohK1wK
[item_reference] => M-AAH-960
[tracking_details] => Array
(
[article_id] => G4KZ00002482EXP00006
[consignment_id] => G4KZ00002482
[barcode_id] => G4KZ00002482EXP00006
)
[product_id] => exp
)
)
I want article_id values in ascending order using loop.
Output will be using ascending ..
article_id G4KZ00002482EXP00002
weight 19.2
article_id G4KZ00002482EXP00003
weight 18.5
article_id G4KZ00002482EXP00006
weight 19.3
article_id G4KZ00002482EXP00007
weight 5.6
I used following script but not given proper result, It's return error.
$result = array(
array('weight'=>5.6, 'item_id'=>'wQsK0EpTSkAAAAFvOVohK1wK','item_reference'=>'M-AAH-960',
'tracking_details'=>array('article_id'=>'G4KZ00002482EXP00007','consignment_id'=>'G4KZ00002482','barcode_id'=>'G4KZ00002482EXP00007'),
'product_id'=>'exp'
),
array('weight'=>19.2, 'item_id'=>'wQsK0EpTSkAAAAFvOVohK1wK','item_reference'=>'M-AAH-960',
'tracking_details'=>array('article_id'=>'G4KZ00002482EXP00002','consignment_id'=>'G4KZ00002482','barcode_id'=>'G4KZ00002482EXP00002'),
'product_id'=>'exp'
),
array('weight'=>18.5, 'item_id'=>'wQsK0EpTSkAAAAFvOVohK1wK','item_reference'=>'M-AAH-960',
'tracking_details'=>array('article_id'=>'G4KZ00002482EXP00003','consignment_id'=>'G4KZ00002482','barcode_id'=>'G4KZ00002482EXP00003'),
'product_id'=>'exp'
),
array('weight'=>19.3, 'item_id'=>'wQsK0EpTSkAAAAFvOVohK1wK','item_reference'=>'M-AAH-960',
'tracking_details'=>array('article_id'=>'G4KZ00002482EXP00006','consignment_id'=>'G4KZ00002482','barcode_id'=>'G4KZ00002482EXP00006'),
'product_id'=>'exp'
),
);
foreach ($result as $key => $value) {
echo $output = sort(array_column($result, 'article_id'));
}
I've created an implementation which gives the output you want
usort($result, function ( $a, $b) {
return ($a['tracking_details']['article_id'] <=> $b['tracking_details']['article_id']);
});
foreach($result as $item) {
print($item['tracking_details']['article_id'].PHP_EOL);
print($item['weight'].PHP_EOL);
print(PHP_EOL);
}
This uses usort and <=> for comparing the article ID-s.
An alternative to the explicit usorts, is to map keys to your article id, and then use array_multisort with the map. You sort the map to sort the result:
<?php
foreach($result as $k => $item)
$map[$k] = $item['tracking_details']['article_id'];
array_multisort($map, $result);
I am trying to sort this multidimensional array based on [sort_order].
I have searched a lot of topics related with no sucess.
Can I have a little help here?
The objective is to sort the array so I can get the array on the following order:
[post_images]
[localizacao]
[post_title]
[category]
Array
(
[[#taxonomy_name#]] => Array
(
[post_title] => Array
(
[name] => post_title
[show_in_email] => 1
[sort_order] => 3
[options] => Array
(
[0] =>
)
)
[post_images] => Array
(
[name] => post_images
[is_active] => 1
[show_on_listing] => 1
[show_on_detail] => 1
[sort_order] => 1
[options] => Array
(
[0] =>
)
)
[category] => Array
(
[name] => category
[is_require] => 1
[is_active] => 1
[show_on_listing] => 1
[show_on_detail] => 1
[show_in_email] => 1
[sort_order] => 4
[options] => Array
(
[0] =>
)
)
[localizacao] => Array
(
[name] => localizacao
[label] => Localização
[htmlvar_name] => localizacao
[sort_order] => 2
[options] => Array
(
[0] =>
)
)
)
)
You may find usort useful, which allows you to sort with a callback function like so:
// The function which will do your comparisons:
function sortOrderCompare ($a, $b) {
$aOrder = $a['sort_order'];
$bOrder = $b['sort_order'];
if ($aOrder == $bOrder) {
// A and B have the same order
return 0;
}else if ($aOrder < $bOrder) {
//A comes before B
return -1;
}else{
// B comes before A
return 1;
}
}
usort($array['[#taxonomy_name#]'], "sortOrderCompare");
You could use array_multisort
Depending on your array structure it looks like this:
foreach( $posts as $post=>$row )
{
$sort_order[$post] = $row['sort_order'];
}
array_multisort( $sort_order, SORT_ASC, $posts );
I have a rather annoying array structure to work with and I need to sort it by any arbitrary key combination. 2 records are displayed below but multiple records with or without the same structure will be present when sorting is actioned.
Here are two records.
Array(
[0] => Array
(
[cid] => 1
[title] => Mr
[first_name] => Abet
[last_name] => Simbad
[emails] => Array
(
[374] => Array
(
[eid] => 374
[name] => ski lodge
[email] => simbad#skifree.com
)
[373] => Array
(
[eid] => 373
[name] => work
[email] => simbad#work.com
)
[375] => Array
(
[eid] => 375
[name] => personal
[email] => simbad#gmail.com
)
)
)
[1] => Array
(
[cid] => 2
[title] => Mrs
[first_name] => Angie
[last_name] => Stokes
[emails] => Array
(
[590] => Array
(
[eid] => 590
[name] => work
[email] => angie#gmail.com
)
)
)
So if I wanted to sort by email in ascending order in the emails array, how can I get the second complete record to come first in the result array? angie#gmail.com comes before simbad#....
Also Some records will not contain an emails array. They would be last in the result set.
Any help would be much appreciated.
The array shown is a cut down version but I have addresses, notes, phones and websites in the same annoying structure. Ideally I could sort with something like
$sort = array('emails','email')
$data = sort_data_func('ASC',$sort,$data);
But anything steps in the right direction will help. :)
Here's some code I have so far
$sort = array('emails','email');
foreach($contacts as $ckey => $c){
if(is_array($c[$sort[0]])){
foreach($c[$sort[0]] as $key1 => $sort0){
if($sort0[$sort[1]]!=''){
$res[$sort[0]][$ckey][$sort[1]][] = $sort0[$sort[1]];
}
}
}
}
print_r($res);
Which produces:
Array
(
[emails] => Array
(
[0] => Array
(
[0] => simbad#skifree.com
[1] => simbad#work.com
[2] => simbad#gmail.com
)
[1] => Array
(
[0] => angie#gmail.com
)
)
)
But I have no idea where to go from here.
EDIT
OK I have the records in the currect order now but how can I keep the initial record ID in the resulting array?
Here's what I'm using.
$direction=='ASC'
function cmp_asc($a, $b){
$key = current(array_keys($a));
sort($a[$key]);
$a[$key] = current($a[$key]);
sort($b[$key]);
$b[$key] = current($b[$key]);
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
function cmp_desc($a, $b){
$key = current(array_keys($a));
asort($a[$key]);
$a[$key] = current($a[$key]);
asort($b[$key]);
$b[$key] = current($b[$key]);
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
if($direction=='ASC'){
usort($res[$sort[0]], 'cmp_asc');
}else{
usort($res[$sort[0]], 'cmp_desc');
}
In
Array
(
[emails] => Array
(
[0] => Array
(
[email] => Array
(
[0] => simbad#skifree.com
[1] => simbad#work.com
[2] => simbad#gmail.com
)
)
[1] => Array
(
[email] => Array
(
[0] => angie#gmail.com
)
)
)
)
Out
Array
(
[emails] => Array
(
[0] => Array
(
[email] => Array
(
[0] => angie#gmnail.com
)
)
[1] => Array
(
[email] => Array
(
[0] => simbad#skifree.com
[1] => simbad#work.com
[2] => simbad#gmail.com
)
)
)
)
One of the usort functions, combined with a self-written comparison function that detects the order in which two elements should be sorted, should do the trick.