1

The array below should be sorted by the first number of cat_url_title in an ascending direction.

Array
(
    [0] => Array
        (
            [cat_id] => 14
            [parent_id] => 2
            [cat_url_title] => 20-a-43m
        )

    [1] => Array
        (
            [cat_id] => 13
            [parent_id] => 2
            [cat_url_title] => 16-a-20m            
        )

    [2] => Array
        (
            [cat_id] => 12
            [parent_id] => 2
            cat_url_title] => 12-a-16m
        )
)

//get the first number
foreach( $arr as $k => $v )
{
    $segs = explode("-",$v['cat_url_title']);
    $nbr = $segs[0]; //this will be 20, 16 or 12
} 

The subarray with the cat_url_title value starting with 12 should become $arr[0], 16 should remain as $arr[1], and 20 should move to $arr[2].

How can I achieve this?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
stef
  • 26,771
  • 31
  • 105
  • 143

6 Answers6

4

usort()

binaryLV
  • 9,002
  • 2
  • 40
  • 42
  • Links support a good answer but don't constitute a good answer in solitude. Please be more generous with your knowledge and edit this post to be more than a redirect. – mickmackusa Dec 09 '19 at 10:38
  • 1
    @mickmackusa, while I agree that it would have been better to write a more complete answer, I'd like to point out that this answer is 8.5 years old and that knowledge has been lost long time ago. – binaryLV Dec 10 '19 at 19:10
  • Old link-only answers with UVs invite new volunteers to mimic the behavior. Not good for this site. – mickmackusa Dec 11 '19 at 10:28
4

you're on a good way, after getting the first numbers create a new array containing the number as a key and the contents of the array as value:

$newArray = array();
foreach($arr as $k => $v)
{
  $segs = explode("-", $v['cat_url_title']);
  $newArray[ $segs[0] ] = $v;
}
ksort($newArray);
print_r($newArray);

that should work.

Joshua - Pendo
  • 4,331
  • 6
  • 37
  • 51
  • sorry! New to Stackoverflow, is this not allowed completely or just a guideline not to give complete solutions? – Joshua - Pendo May 06 '11 at 10:31
  • Guideline from myself :) If you hover mouse on "homework" tag under question, you'll see some description about it. It states that asking questions about homeworks is allowed, "*as long as they are asked honestly, explain the problem, and show sufficient effort*". This makes me think that answers also should be given so that author *has* to *show some effort*. – binaryLV May 06 '11 at 10:35
  • Works! Just wondering, what determines if a question is homework? I graduated a decade ago :) – stef May 06 '11 at 10:39
  • P.S. Other types of questions sometimes desire complete solutions, sometimes they desire just some guidelines (pseudo-code or something) - depends on type of problem. This is just a special case - a *homework*, therefore IMHO we should let him think and just *help* to solve the problem (rather than solve it instead of him). That's the best we can do to help him to become a great programmer some day :) – binaryLV May 06 '11 at 10:44
  • @stef, well... Question is tagget as "homework". We should ask KingCrunch then, why did he add that tag :) Anyway, while this works, I'd advise to look into `usort()` function, as well as take a look at link that was given by p4bl0. PHP has vast collection of functions for working with arrays. – binaryLV May 06 '11 at 10:46
  • One more thing - what happens when multiple array elements have the same `cat_url_title` (or at least the same first part of it)? ;) – binaryLV May 06 '11 at 10:48
  • My guess is that the first number is a unique ID. If not, then you might have to extend the function. Btw, point taken from the homework part! – Joshua - Pendo May 06 '11 at 10:53
  • @PENDO, as stef commented, first number (as well as second number) is distance in meters, e.g., "20-a-43m" means "from 20 to 43 meters". – binaryLV May 06 '11 at 11:42
  • Ah, didn't notice that :-) Ah well, in that case he might need to modify it a little bit, for example $segs[0] - (int)str_replace("m", "", $segs[2]); and sort by difference in distance. – Joshua - Pendo May 06 '11 at 12:48
2

See the usort() php function.

Interesting page about array sorting functions in php: http://us.php.net/manual/en/array.sorting.php

p4bl0
  • 3,846
  • 1
  • 22
  • 21
  • Links support a good answer but don't constitute a good answer in solitude. Please be more generous with your knowledge and edit this post to be more than a redirect. – mickmackusa Dec 09 '19 at 10:39
1

One-liner:

array_multisort(array_map('end', $array), SORT_NUMERIC, $array);

Assuming:

$array = array (
    0 => array (
        'cat_id' => 14,
        'parent_id' => 2,
        'cat_url_title' => '20-a-43m'
    ),
    1 => array (
        'cat_id' => 13,
        'parent_id' => 2,
        'cat_url_title' => '16-a-20m'
    ),
    2 => array (
        'cat_id' => 12,
        'parent_id' => 2,
        'cat_url_title' => '12-a-16m'
    )
);
Tomasz Durka
  • 586
  • 2
  • 9
0

Here is a function I use to sort arrays:

function array_sort($array, $on, $order='SORT_DESC' /*or SORT_ASC*/ )
    {
      $new_array = array();
      $sortable_array = array();

      if (count($array) > 0) {
          foreach ($array as $k => $v) {
              if (is_array($v)) {
                  foreach ($v as $k2 => $v2) {
                      if ($k2 == $on) {
                          $sortable_array[$k] = $v2;
                      }
                  }
              } else {
                  $sortable_array[$k] = $v;
              }
          }

          switch($order)
          {
              case 'SORT_ASC':   
                  asort($sortable_array);
              break;
              case 'SORT_DESC':
                  arsort($sortable_array);
              break;
          }

          foreach($sortable_array as $k => $v) {
              $new_array[] = $array[$k];
          }
      }
      return $new_array;
    } 

Usage:

array_sort($restaurants_top, "score", 'SORT_DESC');

$restaurants_top = a list of restaurants "score" = an array key SORT_DESC = direction of sorting

Andrei Stanca
  • 908
  • 2
  • 11
  • 26
0

Tomasz's suggestion of array_multisort() is a clever, declarative, and concise technique that has been available in php versions for many years. I'd likely use array_multisort() if this task was in my project.

I might suggest, for project stability (in case the data structure is extended/changed), to explicitly name the column to be sorted by. The following snippet also avoids making iterated end() calls.

array_multisort(array_column($array, 'cat_url_title'), SORT_NUMERIC, $array);

I'll show a couple of modern alternatives as an academic exercise.

From PHP7, the spaceship operator also provides a concise syntax. To isolate the numeric substring before the first hyphen cast the strings as integers.

usort($array, function($a, $b) {
    return (int)$a['cat_url_title'] <=> (int)$b['cat_url_title'];
});

From PHP7.4, arrow function syntax makes a usort() call more concise, but arguably more cryptic to read if you are not used to the syntax.

usort($array, fn($a, $b) => (int)$a['cat_url_title'] <=> (int)$b['cat_url_title']);

As with nearly all of my php posts, here is an online demo to prove that all of my snippets function as intended.

Snippets on this page that iterate the input array multiple times should be avoided.


p.s. if you wish to sort the cat_url_title values on the four numeric/alphabetic substrings, you can write these substrings as arrays on each side of the spaceship operator and it will evaluate the substrings from left to right to determine the sorting outcomes.

Code: (Demo)

usort($array, function($a, $b) {
    return (preg_match_all('~[a-z]+|\d+~', $a['cat_url_title'], $out) ? $out[0] : ['','','',''])
           <=> 
           (preg_match_all('~[a-z]+|\d+~', $b['cat_url_title'], $out) ? $out[0] : ['','','','']);
});

p.p.s. This is may a good case for version_compare(). Unfortunately, it is not reliable for the strings in my test battery. Take note of the final position of the 16-a-20n subarray in this demo. I believe that the function is ignoring the final letter because the evaluation is 0 between 16-a-20m and 16-a-20n.

As for your sample strings with consistent a and m substring positions, it works perfectly to naturally sort.

Code: (Demo)

usort($array, function($a, $b) {
    return version_compare($a['cat_url_title'], $b['cat_url_title']);
});
mickmackusa
  • 43,625
  • 12
  • 83
  • 136