Сортировать массив по двум свойствам объекта, используя анонимную функцию - PullRequest
16 голосов
/ 22 декабря 2011

У меня есть следующий массив:

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

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

Ответы [ 8 ]

18 голосов
/ 22 декабря 2011

Предлагаем отправить в массив с $ props

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

Ура!

3 голосов
/ 16 января 2015

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

$result = Arrays::sort($array,
    Comparator::compound(
        Comparator::compareBy('timestamp'),
        Comparator::compareBy('id')
    )
);
3 голосов
/ 22 декабря 2011
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.

2 голосов
/ 04 апреля 2017

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

Вариант 1: порядок ( $ key, $ direction = 'asc' ), где $ key - это свойство объектов, а $ direction - 'asc' или 'desc'

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

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;

}
2 голосов
/ 22 декабря 2011
$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).

1 голос
/ 09 октября 2018

Принятый ответ имеет вариант цикла, который не всегда будет работать.

if($a->$props[$i-1] == $b->$props[$i-1])
     return $a->$props[$i] < $b->$props[$i] ? 1 : -1;

obj1 prop1: foo, prop2: bar, prop3: test

obj2 prop1: foo, prop2: bar, prop3: apple

При $ i = 1 первое сравнение верно, и, поскольку bar не меньше bar, он вернет -1, а не продолжит цикл для вычисления prop3.

Просто к вашему сведению.

У меня есть вариант, который также принимает направление, поэтому каждое свойство можно также отсортировать по возрастанию или убыванию, используя -1 и 1 соответственно.

function sortByProps(&$anArray, $props) {
    usort($anArray, function($a, $b) use ($props) {
        for($i = 0; $i < count($props); $i++) {
            if( $a->{$props[$i][0]} < $b->{$props[$i][0]}) {
                return $props[$i][1];
            }
            else if( $a->{$props[$i][0]} > $b->{$props[$i][0]}) {
                return -1* $props[$i][1];
            }
        }
        return 0;
    });
}

sortByProps($someArray,(array(['name',-1],['address',-1],['occupation',-1],['favorite_food',-1])));
1 голос
/ 17 июня 2018
      function compare_city($a, $b)
      {
        // sort by state
        $retval = strnatcmp($a->state, $b->state);
        // if identical, sort by city
        if(!$retval) $retval = strnatcmp($a->city, $b->city);
        return $retval;
      }

      // sort alphabetically by state and city
      usort($sortable, __NAMESPACE__ . '\compare_city');

Эта функция работала со мной! Ответ найден по адресу: Сортировка массивов объектов SimpleXMLElement

0 голосов
/ 22 декабря 2011

сортировка по произвольному количеству критериев.Я всегда забываю, сортирует ли $ 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;
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...