Сортировка массива по полю или uasort на стероидах

Если часто надо сортировать массив по разным полям, то вручную лень писать callback-функции. А иногда надо сортировать ещё по нескольким полям. Тогда можно запутаться и наделать ошибок.

Кстати, если кто-то не понял, что я такое написал, идите на php.net/uasort и читайте как PHP способствует деградации программистов, потому что теперь почти никто не напишет сам 5 разных способов сортировки массива. В комментариях к документации я нашёл интересную функцию, которую немного доработал.

Теперь для того чтобы отсортировать массив по полю "name" можно писать

PHP:
  1. masort($yourArray, 'name');

Чтобы отсортировать массив по полю "surname", а те у кого одинаковый "surname", по полю "name"

PHP:
  1. masort($yourArray, 'surname, name');

И даже можно так

PHP:
  1. masort($yourArray, 'priority DESC, surname, name');

DESC обязательно писать заглавными. ASC не работает - это вам не SQL.
Пробелы после запятых можно ставить, а можно и не ставить - они trimаются.

А вот и сама функция

PHP:
  1. function masort(&$data, $sortby) {
  2.     static $funcs = array();
  3.  
  4.     if (empty($funcs[$sortby])) {
  5.         $code = "\$c=0;";
  6.         foreach (split(',', $sortby) as $key) {
  7.             $key = trim($key);
  8.             if (strlen($key)>5 && substr($key, -5)==' DESC') {
  9.                 $asc = false;
  10.                 $key = substr($key, 0, strlen($key)-5);
  11.             } else {
  12.                 $asc = true;
  13.             }
  14.  
  15.             $array = array_pop($data);
  16.             array_push($data, $array);
  17.  
  18.             if ($asc) {
  19.                 if(is_numeric($array[$key])) {
  20.                     $code .= "if ( \$c = ((\$a['$key'] == \$b['$key']) ? 0:((\$a['$key'] " . (($asc)?'<':'>') . " \$b['$key']) ? -1 : 1 )) ) return \$c;";
  21.                 } else {
  22.                     $code .= "if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return " . (($asc)?'':'-') . "\$c;\n";
  23.                 }
  24.             }
  25.         }
  26.         $code .= 'return $c;';
  27.         $func = $funcs[$sortby] = create_function('$a, $b', $code);
  28.     } else {
  29.         $func = $funcs[$sortby];
  30.     }
  31.     $func = $funcs[$sortby];
  32.  
  33.     return uasort($data, $func);
  34. }


Понравилось?

  1. Подпишись через RSS
  2. Расскажи о http://php.southpark.com.ua друзьям.
    Все способы хороши: ICQ, E-mail, свой блог, комментарий в чужом блоге или сообщение на форуме
  3. Добавь статью на news2.ru, Хабрахабр или в закладки

Огромное спасибо!

И не стесняйтесь комментировать - у меня стоит плагин, который убирает rel="nofollow" у людей, которые написали больше 5 комментариев.

RSS feed | Trackback URI

8 комментариев »

2007-10-27 23:53:53

Спасибо за статью. Иногда требуется сделать что-то подобное, обычно обходился по деревенски: foreach и запись в новый массив. Теперь буду использовать эту функцию

 
Comment by SeMeN
2008-02-23 14:54:20

А я эту функцию не понял, честно говоря. Вот если бы кто-то обьяснил что тут к чему.

2008-02-23 23:36:49

Эх... Таки деградирует молодое поколение :wink:
Надо либо учить матчасть, либо не париться и просто копипастить

 
 
Comment by SeMeN
2008-02-23 14:56:06

Что такое DESC ?

2008-02-23 23:34:51

Сортировка не А-Я, а Я-А

 
 
Comment by \/!|
2008-03-06 12:47:48

В коде функции ошибочка:
if ($asc) {
if(is_numeric($array[$key])) {
$code .= "if ( \$c = ((\$a['$key'] == \$b['$key']) ? 0:((\$a['$key'] " . (($asc)?'') . " \$b['$key']) ? -1 : 1 )) ) return \$c;";
} else {
$code .= "if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return " . (($asc)?'':'-') . "\$c;\n";
}
}

здесь лишний if ($asc) {...} надо так:

if(is_numeric($array[$key])) {
$code .= "if ( \$c = ((\$a['$key'] == \$b['$key']) ? 0:((\$a['$key'] " . (($asc)?'') . " \$b['$key']) ? -1 : 1 )) ) return \$c;";
} else {
$code .= "if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return " . (($asc)?'':'-') . "\$c;\n";
}

заметил когда передавал DESC. У себя исправил и использую.
Спасибо за функцию!

 
Comment by Victor
2008-03-06 12:48:40

В коде функции ошибочка:
if ($asc) {
if(is_numeric($array[$key])) {
$code .= "if ( \$c = ((\$a['$key'] == \$b['$key']) ? 0:((\$a['$key'] " . (($asc)?'') . " \$b['$key']) ? -1 : 1 )) ) return \$c;";
} else {
$code .= "if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return " . (($asc)?'':'-') . "\$c;\n";
}
}

здесь лишний if ($asc) {...} надо так:

if(is_numeric($array[$key])) {
$code .= "if ( \$c = ((\$a['$key'] == \$b['$key']) ? 0:((\$a['$key'] " . (($asc)?'') . " \$b['$key']) ? -1 : 1 )) ) return \$c;";
} else {
$code .= "if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return " . (($asc)?'':'-') . "\$c;\n";
}

заметил когда передавал DESC. У себя исправил и использую.
Спасибо за функцию!

 
Comment by Victor
2008-03-06 16:33:22

В функции было две баги (портятся ключи, не правильно обрабатывает DESC).
Вот исправленный вариант:

function masort(&$data, $sortby) {
static $funcs = array();

if (empty($funcs[$sortby])) {
$code = "\$c=0;";
foreach ($data as &$array) { break; }
foreach (split(',', $sortby) as $key) {
$key = trim($key);
if (strlen($key)>5 && substr($key, -5)==' DESC') {
$asc = false;
$key = substr($key, 0, strlen($key)-5);
} else {
$asc = true;
}

if(is_numeric($array[$key])) {
$code .= "if ( \$c = ((\$a['$key'] == \$b['$key']) ? 0:((\$a['$key'] " . (($asc)?'') . " \$b['$key']) ? -1 : 1 )) ) return \$c;";
} else {
$code .= "if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return " . (($asc)?'':'-') . "\$c;\n";
}
}
$code .= 'return $c;';
$func = $funcs[$sortby] = create_function('$a, $b', $code);
} else {
$func = $funcs[$sortby];
}

return uasort($data, $func);
}

 
Имя (required)
E-mail (required - never shown publicly)
URL
Текст комментария
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> in your comment.