I take any solution (usort, foreach, ..)!!!
usort($anArray, function ($a, $b) {
return strnatcmp($a['description'], $b['description']);
});
$anArray = [
// ? => [
// 'description' => '10000_0'
// ]
0 => [
'description' => '10000_D2'
],
1 => [
'description' => '10000_D3'
],
2 => [
'description' => '10000_M3'
],
3 => [
'description' => '10000_M4'
]
]
Result (Natural -> at first position = '_0' -> $ident = '_M' after '_0' if its exists):
$result = [
0 => [
'description' => '10000_0'
]
1 => [
'description' => '10000_M3'
],
2 => [
'description' => '10000_M4'
]
3 => [
'description' => '10000_D2'
],
4 => [
'description' => '10000_D3'
],
]
You can modify your sort function to check for the special cases individually then fall back on a regular sorting method.
<?php
$inputArray = [
0 => [
'description' => '10000_D2'
],
1 => [
'description' => '10000_D3'
],
2 => [
'description' => '10000_M3'
],
3 => [
'description' => '10000_M4'
],
4 => [
'description' => '10000_0'
]
];
usort($inputArray, function ($a, $b) {
// _0 first then _M* then alphabetic
//assume only 1 value will be _0?
if (preg_match('/_0$/', $a['description']) === 1){
//"a" ends in _0
return -1;
}
if (preg_match('/_0$/', $b['description']) === 1){
//"b" ends in _0
return 1;
}
if (
preg_match('/_M\d*$/', $a['description']) === 1
&& preg_match('/_M\d*$/', $b['description']) === 1
){
//both have "M" so sort them normally
return strnatcmp($a['description'], $b['description']);
}
if (preg_match('/_M\d*$/', $a['description']) === 1){
//only "a" has _M
return -1;
}
if (preg_match('/_M\d*$/', $b['description']) === 1){
//only "b" has _M
return 1;
}
//neither side has _M or _0 so normal sorting
return strnatcmp($a['description'], $b['description']);
});
echo print_r($inputArray, true);
?>
Output:
Array
(
[0] => Array
(
[description] => 10000_0
)
[1] => Array
(
[description] => 10000_M3
)
[2] => Array
(
[description] => 10000_M4
)
[3] => Array
(
[description] => 10000_D2
)
[4] => Array
(
[description] => 10000_D3
)
)
I'm assuming you will only have a single _0 value. If you could have multiple _0 values then you need to modify the above code to behave like the 3 _M "if" statements.
You can try this :
$anArray = [
0 => [
'description' => '10000_D2'
],
1 => [
'description' => '10000_D3'
],
2 => [
'description' => '10000_M3'
],
3 => [
'description' => '10000_M4'
]
, 4 => [
'description' => '10000_0'
]
, 5 => [
'description' => '10000_15'
]
, 6 => [
'description' => '10000_789'
]
];
usort($anArray, function ($a, $b) {
$tmpa=explode('_',$a['description']);
$tmpb=explode('_',$b['description']);
if(ctype_digit($tmpa[1])&&!ctype_digit($tmpb[1]))
return -1;
if(!ctype_digit($tmpa[1])&&ctype_digit($tmpb[1]))
return 1;
if($tmpa[1][0]==='M'&&$tmpb[1][0]!=='M')
return -1;
if($tmpa[1][0]!=='M'&&$tmpb[1][0]==='M')
return 1;
return strnatcmp($a['description'], $b['description']);
});
print_r($anArray);
and the output is:
Array
(
[0] => Array
(
[description] => 10000_0
)
[1] => Array
(
[description] => 10000_15
)
[2] => Array
(
[description] => 10000_789
)
[3] => Array
(
[description] => 10000_M3
)
[4] => Array
(
[description] => 10000_M4
)
[5] => Array
(
[description] => 10000_D2
)
[6] => Array
(
[description] => 10000_D3
)
)