Как сгруппировать элементы массива, используя первичный и вторичный ключ?

#php #arrays #grouping

#php #массивы #группировка

Вопрос:

У меня есть этот массив:

 Array
(
    [0] => Array
        (
            [id]=>1
            [account_id] => 1
            [object_id] => 43
            [object_type] => PHOTO
            [action_type] => UPLOAD_PHOTO
        )

    [1] => Array
        (
            [id] => 1
            [account_id] => 1
            [object_id] => 42
            [object_type] => PHOTO
            [action_type] => UPLOAD_PHOTO
        )

    [2] => Array
        (
            [id] => 1
            [account_id] => 1
            [object_id] => 41
            [object_type] => PHOTO
            [action_type] => UPLOAD_PHOTO
        )

    [3] => Array
        (
            [id] => 2
            [account_id] => 2
            [object_id] => 1
            [object_type] => USER
            [action_type] => FOLLOW_USER
        )

    [4] => Array
        (
            [id] => 1
            [account_id] => 1
            [object_id] => 2
            [object_type] => USER
            [action_type] => FOLLOW_USER
        )

    [5] => Array
        (
            [id] => 1
            [account_id] => 1
            [object_id] => 1
            [object_type] => PHOTO
            [action_type] => UPLOAD_PHOTO
        )

)
  

Теперь я хочу сгруппировать элементы с одинаковым значением (например UPLOAD_PHOTO ) по идентификатору в качестве первичного ключа и action_type в качестве вторичного ключа, например:

 Array
(
    [0] => Array(
        [id] => 1
        [account_id] => 1
        [actions] => array(
          [1] => array(
              [object_id] => 42
              [object_type] => PHOTO
              [action_type] => UPLOAD_PHOTO
           )
          [2] => array(
              [object_id] => 43
              [object_type] => PHOTO
              [action_type] => UPLOAD_PHOTO
           )
         )      

 ) 
[2] => Array
    (
        [id] => 1
        [account_id] => 1
        [actions] = array(
            [0] => Array
             (
               [object_id] => 3
               [object_type] => USER
               [action_type] => FOLLOW_USER
             )
            [1] => Array
             (
               [object_id] => 4
               [object_type] => USER
               [action_type] => FOLLOW_USER
             )

        )

    )

)
  

Я пробовал некоторые решения, но безуспешно.

Комментарии:

1. Должен ли в первом элементе входного массива отсутствовать [id] атрибут?

2. @MrTrick: да, моя ошибка, извините.

Ответ №1:

При построении вашего выходного массива вы захотите использовать значимые ключи массива. Таким образом, вы можете найти элемент out, к которому необходимо добавить элемент in:

 $in = (...your array...);
$out = array();

foreach($in as $element) {
   $id = $element['id'];
   //If that id hasn't been seen yet, create the out element.
   if (!isset($out[$id])) {
       $out[$id] = array(
           'id'=>$element['id'],
           'account_id' => $element['account_id'],
           'actions' => array()
       );
   }

   //Add that action to the out element
   $out[$id]['actions'][] = array(
       'object_id' => $element['object_id'],
       'object_type' => $element['object_type'],
       'action_type' => $element['action_type']
   );
}
  

Я не уверен, почему ваши входные элементы имеют разные поля… Если это желаемая функция, где один набор возможных полей принадлежит группе идентификаторов, а другой набор принадлежит действию, вы можете сделать это вместо этого (немного менее читаемый, но более гибкий):

 $in = (...your array...);
$out = array();
//These define which fields from an 
//input element belong to the id,
//and which to the action.
$id_fields = array_flip(array('id','account_id','object_user_id');
$action_fields = array_flip(array('object_id','object_type','action_type');

foreach($in as $element) {
   $id = $element['id'];
   //If that id hasn't been seen yet, create the out element.
   if (!isset($out[$id])) {
       $out[$id] = array_intersect_key($element, $id_fields);
       $out[$id]['actions'] = array();
   }

   //Add that action to the out element
   $out[$id]['actions'][] = array_intersect_key($element, $action_fields);
}
  

Это лучшее решение, если входные элементы могут быть разными, потому что, если ожидаемое поле (отличное от 'id' ) отсутствует, скрипт легко справится с этим.