Reputation: 447
i am sorting a multidimensional array by one of the columns using array_multisort. yes, i know this function is not needed to sort by only one column, but this is for code where there could be more columns being sorted on and right now only the one test is failing.
when i run a test i found on the interwebs, it works fine. when i run pretty much the exact same thing with some other test data, it is ALSO sorting on a column i didnt ask it to sort on.
This test returns proper sorted data (value NOT sorted):
$vc_array = array (
0 => array ('id' => 1,'name' => 'xyz','value' => 'abc','order' => 6),
1 => array ('id' => 2,'name' => 'abc','value' => 'xyz','order' => 2),
2 => array ('id' => 3,'name' => 'uvw','value' => 'ghi','order' => 1),
3 => array ('id' => 4,'name' => 'def','value' => 'xyz','order' => 2,),
4 => array ('id' => 5,'name' => 'ghi','value' => 'uvw','order' => 3),
5 => array ('id' => 6,'name' => 'ghi','value' => 'def','order' => 3),
6 => array ('id' => 7,'name' => 'ghi','value' => 'fff','order' => 3)
);
$vc_array_name = array_column($vc_array, 'name');
$out = array_multisort($vc_array_name, SORT_ASC, $vc_array);
var_dump($vc_array); // note the name 'ghi' and the order of the 'value' column. the 'value' column has NOT been sorted, which is what is expected.
Dumped data:
array(7) { [0]=> array(4) { ["id"]=> int(2) ["name"]=> string(3) "abc" ["value"]=> string(3) "xyz" ["order"]=> int(2) } [1]=> array(4) { ["id"]=> int(4) ["name"]=> string(3) "def" ["value"]=> string(3) "xyz" ["order"]=> int(2) } [2]=> array(4) { ["id"]=> int(5) ["name"]=> string(3) "ghi" ["value"]=> string(3) "uvw" ["order"]=> int(3) } [3]=> array(4) { ["id"]=> int(6) ["name"]=> string(3) "ghi" ["value"]=> string(3) "def" ["order"]=> int(3) } [4]=> array(4) { ["id"]=> int(7) ["name"]=> string(3) "ghi" ["value"]=> string(3) "fff" ["order"]=> int(3) } [5]=> array(4) { ["id"]=> int(3) ["name"]=> string(3) "uvw" ["value"]=> string(3) "ghi" ["order"]=> int(1) } [6]=> array(4) { ["id"]=> int(1) ["name"]=> string(3) "xyz" ["value"]=> string(3) "abc" ["order"]=> int(6) } }
This test sorts properly on the 'name' field, but is also sorting on the 'quantity' field which i did NOT request, and do not want that column to be sorted:
$objectListData4 = [
["name" => "package", "quantity" => 1000, "color" => "brown"],
["name" => "box", "quantity" => 1000, "color" => "red"],
["name" => "notebook", "quantity" => 250, "color" => "orange"],
["name" => "pencil", "quantity" => 100, "color" => "yellow"],
["name" => "bag", "quantity" => 150, "color" => "blue"],
["name" => "box", "quantity" => 1200, "color" => "pink"],
["name" => "notebook", "quantity" => 50, "color" => "blue"],
["name" => "package", "quantity" => 1500, "color" => "green"],
["name" => "bag", "quantity" => 500, "color" => "green"],
["name" => "notebook", "quantity" => 100, "color" => "yellow"],
];
$tmp = array_column($objectListData4, 'name');
array_multisort($tmp, SORT_ASC, $objectListData4);
var_dump($objectListData4); // note the name 'notebook' and the order of the 'quantity' column. the 'quantity' column has also been sorted but shouldnt be
Dumped data:
array(10) { [0]=> array(3) { ["name"]=> string(3) "bag" ["quantity"]=> int(150) ["color"]=> string(4) "blue" } [1]=> array(3) { ["name"]=> string(3) "bag" ["quantity"]=> int(500) ["color"]=> string(5) "green" } [2]=> array(3) { ["name"]=> string(3) "box" ["quantity"]=> int(1000) ["color"]=> string(3) "red" } [3]=> array(3) { ["name"]=> string(3) "box" ["quantity"]=> int(1200) ["color"]=> string(4) "pink" } [4]=> array(3) { ["name"]=> string(8) "notebook" ["quantity"]=> int(50) ["color"]=> string(4) "blue" } [5]=> array(3) { ["name"]=> string(8) "notebook" ["quantity"]=> int(100) ["color"]=> string(6) "yellow" } [6]=> array(3) { ["name"]=> string(8) "notebook" ["quantity"]=> int(250) ["color"]=> string(6) "orange" } [7]=> array(3) { ["name"]=> string(7) "package" ["quantity"]=> int(1000) ["color"]=> string(5) "brown" } [8]=> array(3) { ["name"]=> string(7) "package" ["quantity"]=> int(1500) ["color"]=> string(5) "green" } [9]=> array(3) { ["name"]=> string(6) "pencil" ["quantity"]=> int(100) ["color"]=> string(6) "yellow" } }
Can anyone see why the second test is also sorting the quantity when it shouldnt be??
Upvotes: 1
Views: 177
Reputation: 15
Short answer: you cannot use array_multisort() to achieve what you want because if two members compare as equal, their relative order in the sorted array is undefined. (See the note in http://php.net/manual/en/function.array-multisort.php)
It means you cannot expect your "notebooks" to preserve their original order. If they happened to do it, it was just a coincidence.
Here is one solution for you.
function jnlsort($a, $b)//if the names are same, sort by index. Otherwise, sort by name.
{
if (($a['name'] == $b['name']))
{
return strcmp($a['index'], $b['index']);
}
return strcmp($a['name'], $b['name']);
}
foreach($objectListData4 as $index => $obj)//add the index fields to preserve the order
{
$objectListData4[$index]["index"] = $index;
}
usort($objectListData4, 'jnlsort');
foreach($objectListData4 as $index => $obj)//remove the index fields
{
unset($objectListData4[$index]["index"]);
}
Upvotes: 0
Reputation: 21
maybe this question can help you, on the other hand, maybe usort() is a choice
usort($objectListData4, 'cmp');
function cmp($a, $b) {
return strcmp($a['name'], $b['name']);
}
Upvotes: 0
Reputation: 1969
I'm not sure what the cause for your error is, I suspect it's undocumented functionality that array_multisort sorts arrays of arrays by looking for the next available associative key or something.
But a solution to make sure no further sorting will take place is to pass in the array keys as the 2nd sort parameter. Working version of your second given example:
$objectListData4 = [
["name" => "package", "quantity" => 1000, "color" => "brown"],
["name" => "box", "quantity" => 1000, "color" => "red"],
["name" => "notebook", "quantity" => 250, "color" => "orange"],
["name" => "pencil", "quantity" => 100, "color" => "yellow"],
["name" => "bag", "quantity" => 150, "color" => "blue"],
["name" => "box", "quantity" => 1200, "color" => "pink"],
["name" => "notebook", "quantity" => 50, "color" => "blue"],
["name" => "package", "quantity" => 1500, "color" => "green"],
["name" => "bag", "quantity" => 500, "color" => "green"],
["name" => "notebook", "quantity" => 100, "color" => "yellow"],
];
$tmp = array_column($objectListData4, 'name');
array_multisort($tmp, SORT_ASC, array_keys($objectListData4), $objectListData4);
var_dump($objectListData4); // note the name 'notebook' and the order of the 'quantity' column. the 'quantity' column has also been sorted but shouldnt be
And it's output:
array(10) {
[0]=>
array(3) {
["name"]=>
string(3) "bag"
["quantity"]=>
int(150)
["color"]=>
string(4) "blue"
}
[1]=>
array(3) {
["name"]=>
string(3) "bag"
["quantity"]=>
int(500)
["color"]=>
string(5) "green"
}
[2]=>
array(3) {
["name"]=>
string(3) "box"
["quantity"]=>
int(1000)
["color"]=>
string(3) "red"
}
[3]=>
array(3) {
["name"]=>
string(3) "box"
["quantity"]=>
int(1200)
["color"]=>
string(4) "pink"
}
[4]=>
array(3) {
["name"]=>
string(8) "notebook"
["quantity"]=>
int(250)
["color"]=>
string(6) "orange"
}
[5]=>
array(3) {
["name"]=>
string(8) "notebook"
["quantity"]=>
int(50)
["color"]=>
string(4) "blue"
}
[6]=>
array(3) {
["name"]=>
string(8) "notebook"
["quantity"]=>
int(100)
["color"]=>
string(6) "yellow"
}
[7]=>
array(3) {
["name"]=>
string(7) "package"
["quantity"]=>
int(1000)
["color"]=>
string(5) "brown"
}
[8]=>
array(3) {
["name"]=>
string(7) "package"
["quantity"]=>
int(1500)
["color"]=>
string(5) "green"
}
[9]=>
array(3) {
["name"]=>
string(6) "pencil"
["quantity"]=>
int(100)
["color"]=>
string(6) "yellow"
}
}
Upvotes: 1