开发者

How to sort a subarrays by the leading integers of a specific column value?

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 sh开发者_开发问答ould become $arr[0], 16 should remain as $arr[1], and 20 should move to $arr[2].

How can I achieve this?


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.


usort()


See the usort() php function.

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


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'
    )
);


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


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']);
});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜