Anahkiasen / underscore-php

A redacted PHP port of Underscore.js with additional functions and goodies – Available for Composer and Laravel
http://anahkiasen.github.com/underscore-php/
1.12k stars 134 forks source link

Multidimensional arrays individual sorting direction #22

Open awsp opened 10 years ago

awsp commented 10 years ago

I would like to sort the collection like this, but the array is always sorted in DESC order.
The following gives me the correct sorting priority. It sorts availability first, then the count, but they are both in DESC direction.

Is it possible for me to sort them individually in different direction?

Arrays::sort($collection, function($c) {
    return array(
        $c['availability'], // in DESC direction
        $f['books']['count'], // in ASC direction
    );
}, 'desc');

I also tried the following, but then it only sorts by the last sortBy() and ignores my first sortBy().

return Arrays::from($collection)->sortBy(function($f) {
    return $f['availability'];
}, 'desc')->sortBy(function($f) {
    return $f['books']['count'];
}, 'asc');
Anahkiasen commented 10 years ago

I'm assuming we're talking SQL sorting behavior here like so, where availability DESC count ASC would yield something like this no ?

Availability Count
3 1
3 2
2 1
1 1
1 2

I'm not sure this is currently possible with the current implementation since, as you said, sortings overwrite one another. I'll try to take a look into this as soon as I can, in the meantime if you want to send a pull request for this I'll be happy to accept it.

awsp commented 10 years ago

Yes, I would like to sort it like it behaves in SQL. Here is a slightly modified version borrowed from comments of http://php.net/array_multisort so that it accepts dot-notation keys and possibly closures? :D

public function arrayOrderby()
{
    $args = func_get_args();
    $data = array_shift($args);
    foreach ($args as $n => $field) {
        if (is_string($field)) {
            $tmp = array();
            foreach ($data as $key => $row)
                $tmp[$key] = \Underscore\Types\Arrays::get($row, $field);
            $args[$n] = $tmp;
        }
        elseif (is_callable($field)) {
            // Accepting closure? To be implemented...
        }
    }
    $args[] = &$data;
    call_user_func_array('array_multisort', $args);
    return array_pop($args);
}
Usage:
arrayOrderby($collection, 'availability', SORT_ASC, 'books.count', SORT_DESC);

It seems the above function (still incomplete ) sorts the array in the correct way with individual sorting direction.

PS: I think the sortBy() way seems to be cleaner and more logic way to me when dealing with multiple sorting and direction however. :D

PS2: Haven't finished reading all the code, but for some reasons, I couldn't locate where sortBy() is at. I found sort() is at the abstract class of CollectionMethods.