Группировать массив по значениям php

Я пытаюсь сгруппировать массив по его значениям. Ниже мой массив:

$array = Array
(
    0 => Array
        (
            'name' => 'John Doe',
            'age' => '36',
            'code' => '437',                           
            'group' => '1000',
        ),
    1 => Array
        (
            'name' => 'John Doe',
            'age' => '36',
            'code' => '437',                           
            'group' => '7777',
        ),

    2 => Array
        (
            'name' => 'John Doe',
            'age' => '36',
            'code' => '437',                           
            'group' => '7777',
        ),
    3 => Array
        (
            'name' => 'John Doe',
            'age' => '36',
            'code' => '437',                           
            'group' => '4000',
        ),

    4 => Array
        (
            'name' => 'John Doe',
            'age' => '36',
            'code' => '437',                           
            'group' => '4000',
        ),

    5 => Array
        (
            'name' => 'John Doe',
            'age' => '36',
            'code' => '437',                           
            'group' => '5000',
        ),

    6 => Array
        (
            'name' => 'John Doe',
            'age' => '36',
            'code' => '437',                           
            'group' => '6000',
        ),

    7 => Array
        (
            'name' => 'John Doe',
            'age' => '36',
            'code' => '437',                           
            'group' => '6000',
        ),
);

Я пробовал ниже:

$result = array();
    foreach ($array as $key => $record) {
        if (!isset($result[$record['code']])) {
            $result[$record['code']] = array(
                'name' => $record['name'],
                'age' => $record['age'],
                'groups' => array(array($record['code'], $record['group'])),
            );
        }
        else {
            $result[$record['code']]['groups'][] = array($record['code'],$record['group']);
        }
    }
    $result = array_values($result);

    print_r($result);

И я получаю:

Array
(
    [0] => Array
        (
            [name] => John Doe
            [age] => 36
            [groups] => Array
                (
                    [0] => Array
                        (
                            [0] => 437
                            [1] => 1000
                        )

                    [1] => Array
                        (
                            [0] => 437
                            [1] => 7777
                        )

                    [2] => Array
                        (
                            [0] => 437
                            [1] => 7777
                        )

                    [3] => Array
                        (
                            [0] => 437
                            [1] => 4000
                        )

                    [4] => Array
                        (
                            [0] => 437
                            [1] => 4000
                        )

                    [5] => Array
                        (
                            [0] => 437
                            [1] => 5000
                        )

                    [6] => Array
                        (
                            [0] => 437
                            [1] => 6000
                        )

                    [7] => Array
                        (
                            [0] => 437
                            [1] => 6000
                        )

                )

        )

)

Теперь я хочу, чтобы мой массив был сгруппирован по значениям группы 7777, 1000 и другим (все остальные групповые значения):

Array
(
    [0] => Array
        (
            [name] => John Doe
            [age] => 36
            [7777] => Array
                (
                    [0] => Array
                        (
                            [0] => 437
                            [1] => 7777
                        )

                    [1] => Array
                        (
                            [0] => 437
                            [1] => 7777
                        )
                )
            [6000] => Array
                (
                    [0] => Array
                        (
                            [0] => 437
                            [1] => 6000
                        )

                    [1] => Array
                        (
                            [0] => 437
                            [1] => 6000
                        )
                )
            [others] => Array
                (
                    [0] => Array
                        (
                            [0] => 437
                            [1] => 1000
                        )

                    [1] => Array
                        (
                            [0] => 437
                            [1] => 4000
                        )

                    [2] => Array
                        (
                            [0] => 437
                            [1] => 4000
                        )

                    [3] => Array
                        (
                            [0] => 437
                            [1] => 5000
                        )
                )

        )

)

Заранее спасибо.

В чем смысл первого уровня массива? У вас может быть несколько "имени" / "возраста"?

Mickaël Leger 10.08.2018 15:23

Да, ты прав.

Ikarus 10.08.2018 15:25

Я прав по какому пункту? Первый уровень бесполезен или у вас может быть несколько имени / возраста?

Mickaël Leger 10.08.2018 15:26

У меня может быть несколько имен / возрастов.

Ikarus 10.08.2018 15:30

Я отправляю ответ, который выглядит так, как вы хотите, но я не понимаю, как добавлять значение "код" несколько раз

Mickaël Leger 10.08.2018 15:44
0
5
765
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Попробуй это :

// Create a new array
$result = array();

// Loop through your array
foreach ($array as $value) {
    // Create a key that start at 0
    $i = 0;
    // Test if $result[0] exist : if yes, you have data, else you have nothing
    if (isset($result[$i])) {
        do {
            // Check if the 'name' is new : if yes, $i++ to check next name
            if ($result[$i]['name'] !== $value['name']) $i++;
            // If you find similar name, stop here
            else break;
        } while (isset($result[$i]));
    // Just add $result[0] with name and age value
    } else {
        $result[$i] = array (
            'name' => $value['name'],
            'age'  => $value['age']
        );
    }
    // Now you know the index of result you need to work with
    // Just add a new code / group array to your code index
    $result[$i][$value['group']][] = array($value['code'], $value['group']);
}

Если вы сделаете var_dump($result);, результат будет следующим:

array (size=1)
0 => 
  array (size=7)
    'name' => string 'John Doe' (length=8)
    'age' => string '36' (length=2)
    1000 => 
      array (size=1)
        0 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '1000' (length=4)
    7777 => 
      array (size=2)
        0 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '7777' (length=4)
        1 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '7777' (length=4)
    4000 => 
      array (size=2)
        0 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '4000' (length=4)
        1 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '4000' (length=4)
    5000 => 
      array (size=1)
        0 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '5000' (length=4)
    6000 => 
      array (size=2)
        0 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '6000' (length=4)
        1 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '6000' (length=4)

РЕДАКТИРОВАТЬ :

Чтобы получить только значение группы, равное 7777 и 6000, замените

$result[$i][$value['group']][] = array($value['code'], $value['group']);

по

$group_value = $value['group'] == "7777" || $value['group'] == "6000" ? $value['group'] : "Others";
$result[$i][$group_value][] = array($value['code'], $value['group']);

Теперь вывод var_dump($result);:

array (size=1)
  0 => 
  array (size=5)
    'name' => string 'John Doe' (length=8)
    'age' => string '36' (length=2)
    'Others' => 
      array (size=4)
        0 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '1000' (length=4)
        1 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '4000' (length=4)
        2 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '4000' (length=4)
        3 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '5000' (length=4)
    7777 => 
      array (size=2)
        0 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '7777' (length=4)
        1 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '7777' (length=4)
    6000 => 
      array (size=2)
        0 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '6000' (length=4)
        1 => 
          array (size=2)
            0 => string '437' (length=3)
            1 => string '6000' (length=4)

Это то, что ты хочешь?

Извините, в моем вопросе была опечатка. Спасибо за ваш быстрый ответ. :) Это почти решило мою проблему. На самом деле мне нужны только три группы: 7777, 6000 и другие. Другой будет содержать групповые значения 1000, 4000 и 5000).

Ikarus 10.08.2018 16:09

7777 и 6000 статичны? Они не изменятся?

Mickaël Leger 10.08.2018 16:12

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

Я зацикливаю только уникальные имена и уникальные группы внутри этого имени.

$names = array_column($array, "name");
$groups = array_column($array, "group");

foreach(array_unique($names) as $name){
    $intersects = array_intersect_key($array, array_intersect($names, [$name]));
    $new[$name] = ["name" => $name, "age" => end($intersects)["age"]]; // Create the start of the array
    foreach(array_unique($groups) as $group){ // loop only unique groups
        $intersects = array_intersect_key($array, array_intersect($groups, [$group])); // find matching arrays with this group
        foreach($intersects as $int){
            $temp = array_diff($int, ["name" => $new[$name]["name"], "age" => $new[$name]["age"]]); // remove the name and age from the matching array and place them in 6000/7777 or others
            if($temp["group"] == "6000" || $temp["group"] == "7777"){
                $new[$name][$group][] = $temp; 
            }else{
                $new[$name]["others"][] = $temp;
            }
        }
    }
}
var_dump($new);

выход:

array(1) {
  ["John Doe"]=>
  array(5) {
    ["name"]=>
    string(8) "John Doe"
    ["age"]=>
    string(2) "36"
    ["others"]=>
    array(4) {
      [0]=>
      array(2) {
        ["code"]=>
        string(3) "437"
        ["group"]=>
        string(4) "1000"
      }
      [1]=>
      array(2) {
        ["code"]=>
        string(3) "437"
        ["group"]=>
        string(4) "4000"
      }
      [2]=>
      array(2) {
        ["code"]=>
        string(3) "437"
        ["group"]=>
        string(4) "4000"
      }
      [3]=>
      array(2) {
        ["code"]=>
        string(3) "437"
        ["group"]=>
        string(4) "5000"
      }
    }
    [7777]=>
    array(2) {
      [0]=>
      array(2) {
        ["code"]=>
        string(3) "437"
        ["group"]=>
        string(4) "7777"
      }
      [1]=>
      array(2) {
        ["code"]=>
        string(3) "437"
        ["group"]=>
        string(4) "7777"
      }
    }
    [6000]=>
    array(2) {
      [0]=>
      array(2) {
        ["code"]=>
        string(3) "437"
        ["group"]=>
        string(4) "6000"
      }
      [1]=>
      array(2) {
        ["code"]=>
        string(3) "437"
        ["group"]=>
        string(4) "6000"
      }
    }
  }
}

https://3v4l.org/jCKk7

EDIT изменил 1000 на 6000, как указано в комментариях к другому ответу.

Опять же, ваше решение кажется чрезмерно сложным для понимания. Все эти функции array_ требуют большого количества итераций. Моя позиция заключается не в микрооптимизации, а в прямоте и удобочитаемости.

mickmackusa 11.08.2018 09:14

Я не уверен, какова ваша бизнес-логика, но ваш дизайн хранилища данных не оптимален. Избыточные уровни и значения могут и должны быть удалены в соответствии с передовой практикой. Помимо этого совета, решение Mickael, возможно, подведет вас, если ваш входной массив не предварительно отсортирован по значениям code и у вас есть более одного значения code.

Процесс очень простой. Используйте значения code в качестве временных уникальных ключей в выходном массиве. Если вы имеете дело с первым появлением значения code, установите элементы name и age. На каждой итерации добавляйте новый подмассив к выходному массиву на основе значения code и условия значения group. Когда цикл завершится, переиндексируйте выходной массив с помощью array_values().

Код: (Демо)

$array = [
    ['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '1000'],
    ['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '7777'],
    ['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '7777'],
    ['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '4000'],
    ['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '4000'],
    ['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '5000'],
    ['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '6000'],
    ['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '6000']
];

foreach ($array as $row) {
    if (!isset($result[$row['code']])) {
        $result[$row['code']] = ['name' => $row['name'], 'age' => $row['age']];
    }
    $result[$row['code']][in_array($row['group'], ['7777','6000']) ? $row['group'] : 'others'][] = [$row['code'], $row['group']];
}
var_export(array_values($result));

Выход:

array (
  0 => 
  array (
    'name' => 'John Doe',
    'age' => '36',
    'others' => 
    array (
      0 => 
      array (
        0 => '437',
        1 => '1000',
      ),
      1 => 
      array (
        0 => '437',
        1 => '4000',
      ),
      2 => 
      array (
        0 => '437',
        1 => '4000',
      ),
      3 => 
      array (
        0 => '437',
        1 => '5000',
      ),
    ),
    7777 => 
    array (
      0 => 
      array (
        0 => '437',
        1 => '7777',
      ),
      1 => 
      array (
        0 => '437',
        1 => '7777',
      ),
    ),
    6000 => 
    array (
      0 => 
      array (
        0 => '437',
        1 => '6000',
      ),
      1 => 
      array (
        0 => '437',
        1 => '6000',
      ),
    ),
  ),
)

Другие вопросы по теме