如何按列值对子数组进行分组?


74

我有以下数组

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


您是否还想删除重复的????
巴巴2012年

大多数解决方案使用一个FOREACH。
贾斯汀·约翰

@JustinJohn大多数解决方案都使用ONE FOREACH进行数组创建,最终结果不是数组。我一直在寻找更好的解决方案。
红色,

1
您的意思是最终结果不是一维数组。
贾斯汀·约翰

我的意思是..我需要foreach创建的数组以将其转换为html元素的值。
2012年

Answers:


163

没有本机的,只需使用循环即可。

$result = array();
foreach ($data as $element) {
    $result[$element['id']][] = $element;
}

2
您不需要if-真正的部分在两种情况下都有效。
Nicholas Shanks

1
这里不需要if条件。这与相同$result[$id][] = $data。试试看。
Ejaz Karim'7

这怎么知道相似的ID?
FiberOptics

伟大的代码,有类似的问题。但最重要的是,我需要重复ID的数量
巴卡里SHEGHEMBE


36

您可以尝试以下操作:

$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)

27

在更实用的编程风格中,您可以使用 array_reduce

$groupedById = array_reduce($data, function (array $accumulator, array $element) {
  $accumulator[$element['id']][] = $element;

  return $accumulator;
}, []);

18

我只是受.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"
    }
  }
}

8

使用并缓存要分组的列值,然后将其余数据作为结果中创建的组的新子数组推送。

function array_group(array $data, $by_column)
{
    $result = [];
    foreach ($data as $item) {
        $column = $item[$by_column];
        unset($item[$by_column]);
        $result[$column][] = $item;
    }
    return $result;
}

3

这个array_group_by函数可以实现您想要的目标:

$grouped = array_group_by($arr, 'id');

它甚至支持多级分组:

$grouped = array_group_by($arr, 'id', 'part_no');

警告:此方法array_group_by将变量$key作为方法参数引入,并在foreach
DannyFeliz

3

$ arr =数据荒废;

$ 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;
}


2
for($i = 0 ; $i < count($arr)  ; $i++ )
{
    $tmpArr[$arr[$i]['id']] = $arr[$i]['id'];
}
$vmpArr = array_keys($tmpArr);
print_r($vmpArr);

这个答案是非常错误的-它只返回密钥并杀死重复项。它还使用了count()每次调用都会调用的糟糕做法。仅代码的答案对SO而言是低价值的。我可能永远不会理解支持者。
mickmackusa

2

我喜欢@baba的答案,但创建了一个更复杂的三层深度多维(array(array(array(array)))):

$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有零件号。的数量和运输编号212755-1


2

与LINQ无关紧要,后者在PHP中在包括YaLinqo *在内的多个库中实现。它允许对数组和对象执行类似SQL的查询。该groubBy功能是专门为分组而设计的,您只需要指定要分组的字段即可:

$grouped_array = from($array)->groupBy('$v["id"]')->toArray();

该库支持'$v["id"]'的简写形式在哪里function ($v) { return $v["id"]; }

结果将与所接受的答案完全相同,只需要较少的代码。

*由我开发


您能给我一个提示如何按多个字段分组吗?在我的用例中,我有一个带有日期字段的对象,需要按年,月和日分组。像{2016 => {09 => {15 => $ object}}}之类的东西
fnagel

1
@fnagel嵌套分组有些复杂。请参阅有关嵌套groupBy支持问题。它包括一个辅助函数group_by_multiple,以及有关嵌套分组工作原理的详尽解释。使用此功能,您的查询将类似于group_by_multiple($objects, [ '$v->date->format("Y")', '$v->date->format("n")', '$v->date->format("j")' ])
Athari

2

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.检测表(二维数组)的唯一行

此功能用于过滤“行”。如果说二维数组是一个表,那么它的每个元素都是一行。因此,我们可以使用此功能删除重复的行。如果两行(第二维的元素)全部相等,则两行(第一维的元素)相等。比较“列”值适用:如果一个值是简单类型,则该值本身将用于比较;否则(其类型arrayobjectresourceunknown type)将被使用。

策略很简单:从原始数组中创建一个浅层数组,其中的元素是implode原始数组的d个“列”。然后应用array_unique(...)就可以了; 最后使用检测到的ID过滤原始数组。

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应或多或少复杂,ZB 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;
}

1

这应该将关联数组Ejm按国家分组

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'));


1
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;

}


1
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')) 

1

递归函数按从头到尾的键分组二维数组

输入:

$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);
    }
}

-3

我认为这在PHP 5.5+中会更好

$IdVar = array_column($data, 'id');

什么有效?您还指什么?它如何回答这个问题?
Dharman

这只是从数组中提取列值,然后放入数组中。在这种情况下,结果应为['96','97']
user1718607
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.