使用列值对2维数组数据进行分组,创建一个3维数组。

36
我有一个多维数组,想要按特定列中的值对它们进行分组。我想根据`level`进行分组,但我事实上不知道`level`的值。因此,我不能使用`for`循环并说`while $i < 7`,因为我不知道`7`是`level`键的最大值,而且即使我知道也不确定这种方法是否可行。
[
    ['cust' => 'XT8900', 'type' => 'standard', 'level' => 1],
    ['cust' => 'XT8944', 'type' => 'standard', 'level' => 1],
    ['cust' => 'XT8922', 'type' => 'premier', 'level' => 3],
    ['cust' => 'XT8816', 'type' => 'permier', 'level' => 3],
    ['cust' => 'XT7434', 'type' => 'standard', 'level' => 7],
]

期望的结果:

Array (

   [1] => Array (
          [0] => Array (
                    [cust] => XT8900
                    [type] => standard
                    )
          [1] => Array (
                    [cust] => XT8944
                    [type] => standard
                    )
          )

   [3] => Array (
          [2] => Array (
                 [cust] => XT8922
                 [type] => premier
                 )

          [3] => Array (
                 [cust] => XT8816
                 [type] => permier
                 )
          )

   [7] => Array (
          [4] => Array (
                 [cust] => XT7434
                 [type] => standard
                 )
          )
)
8个回答

46

如果你有控制建立初始数组的能力,那么最好的方法就是在添加条目时一开始就将其设置好。

如果不行,那么需要构建一个临时数组进行排序:

foreach ($input_arr as $key => &$entry) {
    $level_arr[$entry['level']][$key] = $entry;
}

让你得到你想要的表格,以及所有相关内容。

如果可能的话,请一开始就像这样构建数组。


我不理解将 $entry 设为引用的好处。 - mickmackusa
@mickmackusa foreach 在某些情况下会复制它正在迭代的数组。明确使用引用意味着您可以确保它不会复制可能是巨大输入数组的内容。我不知道这种微观优化在2023年是否相关,当我最初撰写这个答案时,世界还很年轻 :) - Mike

11

首先需要按照级别将它们分组

使用foreach循环遍历数组,检查级别是否与前一个项目相同,然后将其与该数组分组

  $templevel=0;   

  $newkey=0;

  $grouparr[$templevel]="";

  foreach ($items as $key => $val) {
   if ($templevel==$val['level']){
     $grouparr[$templevel][$newkey]=$val;
   } else {
     $grouparr[$val['level']][$newkey]=$val;
   }
     $newkey++;       
  }
print($grouparr);
print($grouparr); 的输出结果将以您所希望的格式显示。
您也可以尝试:
print($grouparr[7]);

会显示

 [7] => Array (
      [4] => Array (
             [cust] => XT7434
             [type] => standard
             )
      )
或者
print($grouparr[3]);

将显示

[3] => Array (
      [2] => Array (
             [cust] => XT8922
             [type] => premier
             )

      [3] => Array (
             [cust] => XT8816
             [type] => permier
             )
      )

我认为你代码中的“if”子句是多余的,因为行“$grouparr[$val['level']][$newkey]=$val;”适用于所有情况。换句话说,这一行也适用于“$templevel”等于“$val ['level']”的情况。因此,在那种情况下,代码将只是:$templevel=0; $newkey=0; foreach ($items as $key => $val) { $grouparr[$val['level']][$newkey]=$val; $newkey++; } print($grouparr); - vasilis

7

以下是我为类似问题找到的解决方案,封装成了一个函数:

function arraySort($input,$sortkey){
  foreach ($input as $key=>$val) $output[$val[$sortkey]][]=$val;
  return $output;
}

要按照名为“level”的键对$myarray进行排序,请执行以下操作:

$myArray = arraySort($myArray,'level');

如果您不想将其作为函数,仅用于一次使用,那么此代码将通过键“level”将$myArray分组创建$myNewArray。

foreach ($myArray as $key=>$val) $myNewArray[$val['level']][]=$val;

这是一个非常有用的答案。我正在尝试使用它,但希望$val成为唯一值。你有什么建议吗? - drew schmaltz
这个答案没有提供OP想要的输出,因为它没有递增子数组键。证明:http://sandbox.onlinephpfunctions.com/code/22f19e9426fe3133ebd462e469a393730a4e16a1 - mickmackusa

7
function group_assoc($array, $key) {
    $return = array();
    foreach($array as $v) {
        $return[$v[$key]][] = $v;
    }
    return $return;
}

//Group the requests by their account_id
$account_requests = group_assoc($requests, 'account_id');

2
这篇文章不仅自我解释能力差,而且没有按照OP的要求递增子数组键。此外,它甚至没有尊重问题中的关键值——account_id与此问题无关。出于所有这些原因,我很惊讶它已经获得了这么多赞,我已经根据原则进行了反对投票。证明:http://sandbox.onlinephpfunctions.com/code/28f553b4ee2670dc30cb448cfc039bb380b1cba4 我关心这个网站上旧内容的质量,因为我会在适当时候使用它来关闭新问题。 - mickmackusa

1
为了从示例输入生成问题的精确期望输出,请从每一行中提取/弹出最后一个值,并将该值用作第一级分组键。然后使用原始的第一级索引作为第二级键。然后将剩余的两个元素推入群集子集。
代码:(Demo)
$result = [];
foreach ($array as $key => $row) {
    $result[array_pop($row)][$key] = $row;
}
var_export($result);

对于函数式语法,请使用array_reduce()。(演示

var_export(
    array_reduce(
        array_keys($array),
        function($result, $key) use ($array) {
            $result[array_pop($array[$key])][$key] = $array[$key];
            return $result;
        }
    )
);

0
  $result = array();
    foreach ($yourArrayList as $data) {
        $id = $data['level'];
        if (isset($result[$id])) {
            $result[$id][] = $data;
        } else {
            $result[$id] = array($data);
        }
    }

1
仅提供代码的答案在StackOverflow上价值较低,因为它们无法很好地教育OP和未来的研究人员--每个答案(即使是基本的)都应该包括关于解决方案如何工作以及为什么建议这样做的某种解释。此答案不提供所需的输出,因为它不会递增子数组键。证明:http://sandbox.onlinephpfunctions.com/code/93b556d049b09822383c375d189765e4f3050398 - mickmackusa

0

最佳答案。

    $levels = array_unique(array_column($records, 'level'));

    $data = array();

    foreach($records as $key => $value){ 

    $data[$levels[array_search($value['level'],$levels )]][] = $value ; 

    }

    print_r($data); 

1
不鼓励只提供代码的答案。请点击编辑并添加一些概括您的代码如何解决问题的话语,或者解释您的答案与先前答案的区别。谢谢。 - Nick

-2
function _group_by($array,$key,$keyName)
    {
          $return = array();

          foreach($array as $val) {
              $return[$keyName.$val[$key]][] = $val;
          }
         return $return;

    }  //end of function

1
这个答案没有提供任何逻辑或解释。我不知道$key$keyName应该保存什么。我已经给这个答案投了反对票,因为我无法理解它,也不知道该向函数提供什么值。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接