Я пытаюсь сгруппировать массив по его значениям. Ниже мой массив:
$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 ) ) ) )
Заранее спасибо.
Да, ты прав.
Я прав по какому пункту? Первый уровень бесполезен или у вас может быть несколько имени / возраста?
У меня может быть несколько имен / возрастов.
Я отправляю ответ, который выглядит так, как вы хотите, но я не понимаю, как добавлять значение "код" несколько раз
Попробуй это :
// 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).
7777 и 6000 статичны? Они не изменятся?
Вот один метод, который сильно зависит от 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"
}
}
}
}
EDIT изменил 1000 на 6000, как указано в комментариях к другому ответу.
Опять же, ваше решение кажется чрезмерно сложным для понимания. Все эти функции array_
требуют большого количества итераций. Моя позиция заключается не в микрооптимизации, а в прямоте и удобочитаемости.
Я не уверен, какова ваша бизнес-логика, но ваш дизайн хранилища данных не оптимален. Избыточные уровни и значения могут и должны быть удалены в соответствии с передовой практикой. Помимо этого совета, решение 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',
),
),
),
)
В чем смысл первого уровня массива? У вас может быть несколько "имени" / "возраста"?