1

How to sort multidimensional array. This is what my array looks like

[0] => Array
    (
      [id] => 1
      [title] => 3A
      [active] => 1
    )
[1] => Array
    (
      [id] => 1
      [title] => A
      [active] => 1
    )
[2] => Array
    (
      [id] => 1
      [title] => 2A
      [active] => 1
    )
[3] => Array
    (
      [id] => 1
      [title] => B
      [active] => 1
    )

I have tried several usort methods, but cannot seem to get this to work. I am needing the array sorted so that it will sort by numeric then by alpha numeric like so: A,B,2A,3A. I am not sure if this would be possible without adding a position field to dictate what order the titles are suppose to be in, or am I missing something here?

1
  • You sort is not clear. You want to sort by numeric ASC and then by alpha numeric ASC ? Your results will be 2A, 3A, A, B so. Commented Mar 8, 2017 at 16:35

3 Answers 3

1

You can build a "key" for each item where the digit part is padded on the left with 0s, this way, the sort function can perform a simple string comparison:

$temp = [];

foreach ($arr as $v) {
    $key = sscanf($v['title'], '%d%s');
    if (empty($key[0])) $key = [ 0, $v['title'] ];
    $key = vsprintf("%06d%s", $key);
    $temp[$key] = $v;
}

ksort($temp);

$result = array_values($temp);

demo

This technique is called a "Schwartzian Transform".

Sign up to request clarification or add additional context in comments.

Comments

0

As @Kargfen said, you can use usort with your custom function. Like this one :

usort($array, function(array $itemA, array $itemB) {
   return myCustomCmp($itemA['title'], $itemB['title']);
}); 

function myCustomCmp($titleA, $titleB) {
    $firstLetterA = substr($titleA, 0, 1);
    $firstLetterB = substr($titleB, 0, 1);

    //Compare letter with letter or number with number -> use classic sort
    if((is_numeric($firstLetterA) && is_numeric($firstLetterB)) || 
    (!is_numeric($firstLetterA) && !is_numeric($firstLetterB)) ||
    ($firstLetterA === $firstLetterB)
    ) {
        return strcmp($firstLetterA, $firstLetterB);
    }

    //Letters first, numbers after
    if(! is_numeric($firstLetterA)) {
        return -1;
    }

    return 1;
}

This compare-function is just based on the first letter of your titles, but it can do the job ;-)

Comments

0

You can resolve that problem with help of usort and custom callback:

function customSort($a, $b)
{
    if ($a['id'] == $b['id']) {
        //if there is no number at the beginning of the title, I add '1' to temporary variable
        $aTitle = is_numeric($a['title'][0]) ? $a['title'] : ('1' . $a['title']);
        $bTitle = is_numeric($b['title'][0]) ? $b['title'] : ('1' . $b['title']);

        if ($aTitle != $bTitle) {
            return ($aTitle < $bTitle) ? -1 : 1;
        }
        return 0;
    }
    return ($a['id'] < $b['id']) ? -1 : 1;
}

usort($array, "customSort");

At first the function compares 'id' values and then if both items are equal it checks 'title' values.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.