Сортировка массива двумя свойствами объекта с использованием анонимной функции
У меня есть следующий массив:
Array
(
[0] => stdClass Object
(
[timestamp] => 1
[id] => 10
)
[1] => stdClass Object
(
[timestamp] => 123
[id] => 1
)
[2] => stdClass Object
(
[timestamp] => 123
[id] => 2
)
)
В настоящее время я использую следующий код для сортировки массива по свойству timestamp:
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
Предложение - отправить массив с $реквизитом
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;
});
}
Ура!
Ответ 2
Вы можете сделать это с помощью ouzo goodies (я знаю, вы слышали об этом: P).
$result = Arrays::sort($array,
Comparator::compound(
Comparator::compareBy('timestamp'),
Comparator::compareBy('id')
)
);
Ответ 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
.
Ответ 4
$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)
.
Ответ 5
Я знаю, что это довольно старый вопрос, однако не нашел много информации о том, когда вы хотите сортировать по нескольким свойствам вроде mySQL ORDERBY делает здесь функцию из личной структуры
Вариант 1: порядок ($key, $direction = 'asc'), где $key является свойством объектов, а $direction - 'asc' или 'desc'
Вариант 2: порядок (массив ($ key = > $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;
}
Ответ 6
сортировка по произвольному числу критериев. Я всегда забываю, если $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;
});