Сортировка списка объектов по заданным полям в многомерный массив
Есть список объектов $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;
}
}
Всем добра!