2011-12-22 5 views
13

У меня есть следующий массив:Сортировка массива по двум свойствам объекта, используя анонимные функции

Array 
(
    [0] => stdClass Object 
     (
      [timestamp] => 1 
      [id] => 10 
     ) 

    [1] => stdClass Object 
     (
      [timestamp] => 123 
      [id] => 1 
     ) 

    [2] => stdClass Object 
     (
      [timestamp] => 123 
      [id] => 2 
     ) 

) 

В настоящее время я использую следующий код для сортировки массива по свойству временной метки:

function sort_comments_by_timestamp(&$comments, $prop) 
{ 
    usort($comments, function($a, $b) use ($prop) { 
     return $a->$prop < $b->$prop ? 1 : -1; 
    }); 
} 

Как могу ли я также сортировать id по id по убыванию, когда timestamp одинакова?

+1

Есть ли причина, по которой вы называете ее '_by_timestamp', но также имеете параметр' $ prop'? – Matthew

+1

@ Матвей, кроме «Я делал некоторые тесты» и «плохое имя»? Нет :) Уже исправлено это btw – PeeHaa

ответ

17

Предложение, чтобы отправить в массив с $ реквизита

function sort_comments_by_timestamp(&$comments, $props) 
{ 
    usort($comments, function($a, $b) use ($props) { 
     if($a->$props[0] == $b->$props[0]) 
      return $a->$props[1] < $b->$props[1] ? 1 : -1; 
     return $a->$props[0] < $b->$props[0] ? 1 : -1; 
    }); 
} 

И затем вызвать его с

sort_comments_by_timestamp($unsorted_array,array("timestamp","id")); 

Если вы хотите работать с X число $ реквизита вы можете сделать петлю внутри usort всегда сравнивает свойство со своим предыдущим свойством в массиве следующим образом:

function sort_comments_by_timestamp(&$comments, $props) 
{ 
    usort($comments, function($a, $b) use ($props) { 
     for($i = 1; $i < count($props); $i++) { 
      if($a->$props[$i-1] == $b->$props[$i-1]) 
       return $a->$props[$i] < $b->$props[$i] ? 1 : -1; 
     } 
     return $a->$props[0] < $b->$props[0] ? 1 : -1; 
    }); 
} 

Cheers!

+1

Если вы получите ошибку: 'Array to string conversion' вам нужно заменить все $ A-> $ реквизиты [X]' на '$ a-> {$ реквизиты [X]}' –

2
$result = -1; 
if ($a->timestamp < $b->timestamp) { 
    $result = 1; 
} else if ($a->timestamp === $b->timestamp) { 
    if ($a->id < $b->id) $result = 1; 
} 
return $result; 

Положите это в закрытие usort. Вы также можете избавиться от аргумента $ prop и части use ($prop).

3
function sort_comments_by_timestamp(&$comments, $prop) 
{ 
    usort($comments, function($a, $b) use ($prop) { 
     if ($a->$prop == $b->$prop) 
      return $b->id - $a->id; 
     else 
      return $a->$prop < $b->$prop ? 1 : -1; 
    }); 
} 

Вышеуказанные виды первыми параметром $prop, а затем с помощью вторичных id.

0

сортировка по произвольному числу критериев. Я всегда забываю, если $ a - $ b сортируется по возрастанию или по убыванию. При необходимости отрегулируйте.

$comparatorSequence = array(
    function($a, $b) { 
     return $a->timestamp - $b->timestamp; 
    } 
    , function($a, $b) { 
     return $a->id - $b->id; 
    } 
); 

usort($theArray, function($a, $b) use ($comparatorSequence) { 
    foreach ($comparatorSequence as $cmpFn) { 
     $diff = call_user_func($cmpFn, $a, $b); 
     if ($diff !== 0) { 
      return $diff; 
     } 
    } 
    return 0; 
}); 
4

Вы можете сделать это с ouzo goodies (я знаю, что вы слышали об этом: P).

$result = Arrays::sort($array, 
    Comparator::compound(
     Comparator::compareBy('timestamp'), 
     Comparator::compareBy('id') 
    ) 
); 
2

Я знаю, что это довольно старый вопрос, однако не нашел много информации для того, когда вы хотите отсортировать по нескольким свойствам вроде как MYSQL OrderBy делает так что здесь функция из личной базы

Option 1: заказ ($ ключа, $ направление = «по возрастанию»), где $ ключ представляет собой свойство объектов и $ направления «по возрастанию» или «по убыванию»

Вариант 2: заказ (массива ($ ключ => $ direction, $ key => $ direction)) Это похоже на вариант 1, однако, когда 2 объекта имеют одинаковое значение для ключа $, используется второй параметр сортировки из переданного массива.

public function order($arr, $key=null, $direction='ASC'){ 
    if(!is_string($key) && !is_array($key)) 
     throw new InvalidArgumentException("order() expects the first parameter to be a valid key or array"); 

    $props = array(); 

    if(is_string($key)) { 
     $props[$key] = strtolower($direction) == 'asc' ? 1 : -1; 
    }else{ 
     $i = count($key); 
     foreach($key as $k => $dir){ 
      $props[$k] = strtolower($dir) == 'asc' ? $i : -($i); 
      $i--; 
     } 
    } 

    usort($arr, function($a, $b) use ($props){ 
     foreach($props as $key => $val){ 
      if($a->$key == $b->$key) continue; 
      return $a->$key > $b->$key ? $val : -($val); 
     } 
     return 0; 
    }); 

    return $arr; 

} 
+0

Хорошо.Спасибо. – shanebp

+0

Очень приветствуется :) –

+0

Очень симпатичная маленькая функция. Я использовал принятый ответ для моих потребностей сортировки (с некоторыми личными настройками), и он решил прекратить работу после обновления CMS на веб-сайте.Это спасло мне кучу времени, пытаясь отладить проблему. –

Смежные вопросы