Ответ 1
Нет родного, просто используйте цикл.
$result = array();
foreach ($data as $element) {
$result[$element['id']][] = $element;
}
У меня есть следующий массив
Array
(
[0] => Array
(
[id] => 96
[shipping_no] => 212755-1
[part_no] => reterty
[description] => tyrfyt
[packaging_type] => PC
)
[1] => Array
(
[id] => 96
[shipping_no] => 212755-1
[part_no] => dftgtryh
[description] => dfhgfyh
[packaging_type] => PC
)
[2] => Array
(
[id] => 97
[shipping_no] => 212755-2
[part_no] => ZeoDark
[description] => s%c%s%c%s
[packaging_type] => PC
)
)
Как я могу группировать массив с помощью id
? Существуют ли какие-либо встроенные функции php для этого?
Если я foreach
выше, то я получу дубликат, как я могу избежать этого?
В приведенном выше примере id
имеется 2 элемента, поэтому его необходимо находиться внутри id
.
РЕДАКТИРОВАТЬ: ВСЕ РАБОТЫ ТЯЖЕСТИ: НО ЕСТЬ ЛИ КАКИЕ-ЛИБО ПУТЕМ, ЧТОБЫ ДОСТИГНУТЬ ОДИН САМЫЙ ОДИН ФОРЕКС?
Нет родного, просто используйте цикл.
$result = array();
foreach ($data as $element) {
$result[$element['id']][] = $element;
}
Вы можете попробовать следующее:
$group = array();
foreach ( $array as $value ) {
$group[$value['id']][] = $value;
}
var_dump($group);
Вывод:
array
96 =>
array
0 =>
array
'id' => int 96
'shipping_no' => string '212755-1' (length=8)
'part_no' => string 'reterty' (length=7)
'description' => string 'tyrfyt' (length=6)
'packaging_type' => string 'PC' (length=2)
1 =>
array
'id' => int 96
'shipping_no' => string '212755-1' (length=8)
'part_no' => string 'dftgtryh' (length=8)
'description' => string 'dfhgfyh' (length=7)
'packaging_type' => string 'PC' (length=2)
97 =>
array
0 =>
array
'id' => int 97
'shipping_no' => string '212755-2' (length=8)
'part_no' => string 'ZeoDark' (length=7)
'description' => string 's%c%s%c%s' (length=9)
'packaging_type' => string 'PC' (length=2)
Я просто бросил это вместе, вдохновленный .NET LINQ
<?php
// callable type hint may be "closure" type hint instead, depending on php version
function array_group_by(array $arr, callable $key_selector) {
$result = array();
foreach ($arr as $i) {
$key = call_user_func($key_selector, $i);
$result[$key][] = $i;
}
return $result;
}
$data = array(
array(1, "Andy", "PHP"),
array(1, "Andy", "C#"),
array(2, "Josh", "C#"),
array(2, "Josh", "ASP"),
array(1, "Andy", "SQL"),
array(3, "Steve", "SQL"),
);
$grouped = array_group_by($data, function($i){ return $i[0]; });
var_dump($grouped);
?>
И ты получишь
array(3) {
[1]=>
array(3) {
[0]=>
array(3) {
[0]=>
int(1)
[1]=>
string(4) "Andy"
[2]=>
string(3) "PHP"
}
[1]=>
array(3) {
[0]=>
int(1)
[1]=>
string(4) "Andy"
[2]=>
string(2) "C#"
}
[2]=>
array(3) {
[0]=>
int(1)
[1]=>
string(4) "Andy"
[2]=>
string(3) "SQL"
}
}
[2]=>
array(2) {
[0]=>
array(3) {
[0]=>
int(2)
[1]=>
string(4) "Josh"
[2]=>
string(2) "C#"
}
[1]=>
array(3) {
[0]=>
int(2)
[1]=>
string(4) "Josh"
[2]=>
string(3) "ASP"
}
}
[3]=>
array(1) {
[0]=>
array(3) {
[0]=>
int(3)
[1]=>
string(5) "Steve"
[2]=>
string(3) "SQL"
}
}
}
В более функциональном стиле программирования вы можете использовать array_reduce
$groupedById = array_reduce($data, function (array $accumulator, array $element) {
$accumulator[$element['id']][] = $element;
return $accumulator;
}, []);
Мне тоже нужна была такая функция. Я создал этот, вы передаете, какой столбец вы хотите группировать:
function array_group(array $data, $by_column)
{
$result = [];
foreach ($data as $item) {
$column = $item[$by_column];
unset($item[$by_column]);
if (isset($result[$column])) {
$result[$column][] = $item;
} else {
$result[$column] = array($item);
}
}
return $result;
}
for($i = 0 ; $i < count($arr) ; $i++ )
{
$tmpArr[$arr[$i]['id']] = $arr[$i]['id'];
}
$vmpArr = array_keys($tmpArr);
print_r($vmpArr);
Эта функция array_group_by обеспечивает то, что вы ищете:
$grouped = array_group_by($arr, 'id');
Он даже поддерживает многоуровневые группировки:
$grouped = array_group_by($arr, 'id', 'part_no');
1. GROUP BY
один ключ
Эта функция работает как GROUP BY
для массива, но с одним важным ограничением: возможна только одна группировка "столбец" ($identifier
).
function arrayUniqueByIdentifier(array $array, string $identifier)
{
$ids = array_column($array, $identifier);
$ids = array_unique($ids);
$array = array_filter($array,
function ($key, $value) use($ids) {
return in_array($value, array_keys($ids));
}, ARRAY_FILTER_USE_BOTH);
return $array;
}
2. Обнаружение уникальных строк для таблицы (двухмерный массив)
Эта функция предназначена для фильтрации "строк". Если мы говорим, что двумерный массив является таблицей, то каждый его элемент представляет собой строку. Таким образом, мы можем удалить дублированные строки с помощью этой функции. Две строки (элементы первого измерения) равны, если все их столбцы (элементы второго измерения) равны. Для сравнения значений столбца применяется: Если значение имеет простой type, само значение будет использоваться при сравнении; в противном случае его тип (array
, object
, resource
, unknown type
) будет использоваться.
Стратегия проста: сделать из исходного массива мелким массивом, где элементы implode
d "столбцы" исходного массива; затем примените к нему array_unique(...)
; и в качестве последнего используют обнаруженные идентификаторы для фильтрации исходного массива.
function arrayUniqueByRow(array $table = [], string $implodeSeparator)
{
$elementStrings = [];
foreach ($table as $row) {
// To avoid notices like "Array to string conversion".
$elementPreparedForImplode = array_map(
function ($field) {
$valueType = gettype($field);
$simpleTypes = ['boolean', 'integer', 'double', 'float', 'string', 'NULL'];
$field = in_array($valueType, $simpleTypes) ? $field : $valueType;
return $field;
}, $row
);
$elementStrings[] = implode($implodeSeparator, $elementPreparedForImplode);
}
$elementStringsUnique = array_unique($elementStrings);
$table = array_intersect_key($table, $elementStringsUnique);
return $table;
}
Также возможно улучшить сравнение, обнаружив класс значений столбца, если его тип object
.
$implodeSeparator
должен быть более или менее сложным, z.B. spl_object_hash($this)
.
3. Обнаружение строк с уникальными столбцами идентификатора для таблицы (двухмерный массив)
Это решение зависит от второго. Теперь полный "ряд" не обязательно должен быть уникальным. Две "строки" (элементы первого измерения) теперь равны, если все соответствующие "поля" (элементы второго измерения) одной "строки" равны соответствующим "полям" (элементы с одним и тем же ключом).
"Соответствующие" "поля" - это "поля" (элементы второго измерения), которые имеют ключ, равный одному из элементов прошедших "идентификаторов".
function arrayUniqueByMultipleIdentifiers(array $table, array $identifiers, string $implodeSeparator = null)
{
$arrayForMakingUniqueByRow = $removeArrayColumns($table, $identifiers, true);
$arrayUniqueByRow = $arrayUniqueByRow($arrayForMakingUniqueByRow, $implodeSeparator);
$arrayUniqueByMultipleIdentifiers = array_intersect_key($table, $arrayUniqueByRow);
return $arrayUniqueByMultipleIdentifiers;
}
function removeArrayColumns(array $table, array $columnNames, bool $isWhitelist = false)
{
foreach ($table as $rowKey => $row) {
if (is_array($row)) {
if ($isWhitelist) {
foreach ($row as $fieldName => $fieldValue) {
if (!in_array($fieldName, $columnNames)) {
unset($table[$rowKey][$fieldName]);
}
}
} else {
foreach ($row as $fieldName => $fieldValue) {
if (in_array($fieldName, $columnNames)) {
unset($table[$rowKey][$fieldName]);
}
}
}
}
}
return $table;
}
Расширение на @baba ответ, который мне нравится, но создает более сложный трехуровневый многомерный массив (массив (массив)):
$group = array();
foreach ( $array as $value ) {
$group[$value['id']][] = $value;
}
// output only data from id 96
foreach ($group as $key=>$value) { //outer loop
foreach ($value as $k=>$v){ //inner loop
if($key==96){ //if outer loop is equal to 96 (could be variable)
for ($i=0;$i<count($k);$i++){ //iterate over the inner loop
printf($key.' has a part no. of '.$v['part_no'].' and shipping no. of '.$v['shipping_no'].'<br>');
}
}
}
}
Будет выводиться:
96 имеет номер детали. ретрансляции и отгрузочного номера 212755-1
96 имеет номер детали. dftgtryh и номер доставки 212755-1
Это тривиально для LINQ, который реализован в PHP в нескольких библиотеках, включая YaLinqo *. Он позволяет выполнять SQL-запросы на массивы и объекты. Функция groubBy
предназначена специально для группировки, вам просто нужно указать поле, которое вы хотите сгруппировать:
$grouped_array = from($array)->groupBy('$v["id"]')->toArray();
Где '$v["id"]'
является сокращением для function ($v) { return $v["id"]; }
, которое поддерживает эта библиотека.
Результат будет точно таким же, как в принятом ответе, с меньшим количеством кода.
*, разработанный мной
$arr = array();
foreach($old_arr as $key => $item)
{
$arr[$item['id']][$key] = $item;
}
ksort($arr, SORT_NUMERIC);
Это должно группировать ассоциативный массив Ejm Group По странам
function getGroupedArray($array, $keyFieldsToGroup) {
$newArray = array();
foreach ($array as $record)
$newArray = getRecursiveArray($record, $keyFieldsToGroup, $newArray);
return $newArray;
}
function getRecursiveArray($itemArray, $keys, $newArray) {
if (count($keys) > 1)
$newArray[$itemArray[$keys[0]]] = getRecursiveArray($itemArray, array_splice($keys, 1), $newArray[$itemArray[$keys[0]]]);
else
$newArray[$itemArray[$keys[0]]][] = $itemArray;
return $newArray;
}
$countries = array(array('Country'=>'USA', 'State'=>'California'),
array('Country'=>'USA', 'State'=>'Alabama'),
array('Country'=>'BRA', 'State'=>'Sao Paulo'));
$grouped = getGroupedArray($countries, array('Country'));
use function \nspl\a\indexed;
$grouped = indexed($data, 'id');
function array_group_by($arr, array $keys) {
if (!is_array($arr)) {
trigger_error('array_group_by(): The first argument should be an array', E_USER_ERROR);
}
if (count($keys)==0) {
trigger_error('array_group_by(): The Second argument Array can not be empty', E_USER_ERROR);
}
// Load the new array, splitting by the target key
$grouped = [];
foreach ($arr as $value) {
$grouped[$value[$keys[0]]][] = $value;
}
// Recursively build a nested grouping if more parameters are supplied
// Each grouped array value is grouped according to the next sequential key
if (count($keys) > 1) {
foreach ($grouped as $key => $value) {
$parms = array_merge([$value], [array_slice($keys, 1,count($keys))]);
$grouped[$key] = call_user_func_array('array_group_by', $parms);
}
}
return $grouped;
}
$ arr = Data Araay;
$ fldName = Группировать по имени столбца;
function array_group_by( $arr, $fldName) {
$groups = array();
foreach ($arr as $rec) {
$groups[$rec[$fldName]] = $rec;
}
return $groups;
}
function object_group_by( $obj, $fldName) {
$groups = array();
foreach ($obj as $rec) {
$groups[$rec->$fldName] = $rec;
}
return $groups;
}
function groupeByPHP($array,$indexUnique,$assoGroup,$keepInOne){
$retour = array();
$id = $array[0][$indexUnique];
foreach ($keepInOne as $keep){
$retour[$id][$keep] = $array[0][$keep];
}
foreach ($assoGroup as $cle=>$arrayKey){
$arrayGrouped = array();
foreach ($array as $data){
if($data[$indexUnique] != $id){
$id = $data[$indexUnique];
foreach ($keepInOne as $keep){
$retour[$id][$keep] = $data[$keep];
}
}
foreach ($arrayKey as $val){
$arrayGrouped[$val] = $data[$val];
}
$retour[$id][$cle][] = $arrayGrouped;
$retour[$id][$cle] = array_unique($retour[$id][$cle],SORT_REGULAR);
}
}
return $retour;
}
Попробуйте эту функцию
groupeByPHP($yourArray,'id',array('desc'=>array('part_no','packaging_type')),array('id','shipping_no'))
Рекурсивная функция группировки 2-мерного массива по ключам от первого до последнего
Входные данные:
$arr = array(
'0' => array(
'key0' => 'value0',
'key1' => 'value1',
'key2' => 'value02',
),
'2' => array(
'key0' => 'value0',
'key1' => 'value1',
'key2' => 'value12',
),
'3' => array(
'key0' => 'value0',
'key1' => 'value3',
'key2' => 'value22',
),
);
$keys = array('key0', 'key1', 'key2');
Выход:
$arr = array(
'value0' => array(
'value1 => array(
'value02' => null,
'value12' => null,
),
'value3' => 'value22',
),
);
Код:
function array_group_by_keys(&$arr, $keys) {
if (count($arr) < 2){
$arr = array_shift($arr[0]);
return;
}
foreach ($arr as $k => $item) {
$fvalue = array_shift($item);
$arr[$fvalue][] = $item;
unset($arr[$k]);
}
array_shift($keys);
foreach ($arr as &$sub_arr) {
array_group_by_keys($sub_arr, $keys);
}
}