Сортировка списка объектов по заданным полям в многомерный массив

Есть список объектов $objs класса Game. PHP:

class Game{
    public $id;
    public $sport;
    public $country;
    public $league;
 
    public function __construct($id,$sport,$country,$league)
    {
        $this->id = $id;
        $this->sport = $sport;
        $this->country = $country;
        $this->league = $league;
    }
}
$objs = [
    new Game(1,'Football','England','Premier League'),
    new Game(4,'Football','England','Premier League'),
    new Game(2,'Football','Europe',''),
    new Game(3,'Tennis','England',''),
];
$structure1=['sport','country','league'];
$structure2=['country','sport','league'];

Цель: задавая динамически структуру ($structure1, $structure2) получать структуру данных (многомерный массив) вида

    Array
    (
        [Football] => Array
            (
                [England] => Array
                    (
                        [Premier League] => Array
                            (
                                [1] => Game Object
                                    (
                                        [id] => 1
                                        [sport] => Football
                                        [country] => England
                                        [league] => Premier League
                                    )
     
                                [4] => Game Object
                                    (
                                        [id] => 4
                                        [sport] => Football
                                        [country] => England
                                        [league] => Premier League
                                    )
     
                            )
     
                    )
     
                [Europe] => Array
                    (
                        [] => Array
                            (
                                [2] => Game Object
                                    (
                                        [id] => 2
                                        [sport] => Football
                                        [country] => Europe
                                        [league] =>
                                    )
     
                            )
     
                    )
     
            )
     
        [Tennis] => Array
            (
                [England] => Array
                    (
                        [] => Array
                            (
                                [3] => Game Object
                                    (
                                        [id] => 3
                                        [sport] => Tennis
                                        [country] => England
                                        [league] =>
                                    )
     
                            )
     
                    )
     
            )
     
    )

Пока делаю так:

PHP:

    $graph=[];
    $graph2=[];
     
    foreach($objs as $obj){
        $graph[$obj->{$structure1[0]}][$obj->{$structure1[1]}][$obj->{$structure1[2]}][$obj->id]=$obj;
        $graph2[$obj->{$structure2[0]}][$obj->{$structure2[1]}][$obj->{$structure2[2]}][$obj->id]=$obj;
    }

но уверен, есть какое-то универсальное решение. Пока ковыряю интернет, но может кто уже решал такую задачу?


Ответы (2 шт):

Автор решения: splash58

Вот, можете взять за основу

/**
 * @param object[] $arr
 * @param array|string $filelds
 * @return object[]
 */
function array_groupby(array $arr, $fields): array
{
    $fields = (array) $fields;
    $res = [];
    foreach ($arr as $item) {
        $point = & $res;
        foreach ($fields as $level) {
            if (! isset($point[$item->$level])) {
                $point[$item->$level] = [];
            }
            $point = & $point[$item->$level];
        }
        $point[] = $item;
    }
    return $res;
}
echo '<pre>';
print_r(array_groupby($objs, $structure1));
→ Ссылка
Автор решения: sphinks_a

Выспался и нашел красивое решение через рекурсию.

    /**
    * @param array $items
    * @param string|array $key
    * @param bool $distinct
    * @return array
    */
    function group($items,$key,$distinct=true){
            if(!is_array($key)) $key=[$key];
     
            $result=[];
            foreach ($items as $item){
                recursive_group($result,$key,$item,$distinct);
            }
            return $result;
        }
     
    function recursive_group(&$result, $keys, $obj, $distinct){
        $key=array_shift($keys);
        if(isset($obj->$key))$index=$obj->$key; else $index=$key;
 
        if(!isset($result[$index])) $result[$index]=[];
        if(count($keys)) recursive_group($result[$index],$keys,$obj,$distinct);
        else {
            if($distinct)$result[$index]=$obj;
            else $result[$index][]=$obj;
        }
    }

Всем добра!

→ Ссылка