旋转关联数组的索引数组

Pivot an indexed array of associative arrays

我要转换为:

$arr = [
    [
        'type' => 'fruit',
        'name' => 'apple',
        'cost' => 1
    ],
    [
        'type' => 'fruit',
        'name' => 'orange',
        'cost' => 2
    ],
    [
        'type' => 'vegetable',
        'name' => 'carrot',
        'cost' => 2.5
    ],
    [
        'type' => 'vegetable',
        'name' => 'avocado',
        'cost' => 3.5
    ]
];

进入这个:

$arr = [
    [
        'type' => 'fruit',
        'apple' => '1',
        'orange' => 2
    ],
    [
        'type' => 'vegetable',
        'carrot' => 2.5,
        'avocado' => 3.5
    ]
];

如您所见,我需要将每个 type 分组到一个数组中并旋转水果 namecost

对于这样的事情,只需按照 Rizier 的建议循环遍历您的数组就可以了。如果您按类型分组,使用类型作为数组键可能是最简单的,因此格式会与您要求的略有不同。您可以像这样访问结果数组:

$fruitItems = $newArr['fruit'];

示例代码如下:

$size = count($itemArray);
$newArr = []; //The array you want to create
for ($i = 0; $i < $size; $i++)
{
    $item = $itemArray[$i];
    $type = $item['type'];
    $name = $item['name'];
    $cost = $item['cost']
    //If your new array doesn't have this type yet, make a sub-array
    //with the type as key
    if (!isset($newArr[$type]))
        $newArr[$type] = [];
    $newArr[$type][$name] = $cost; //In your type sub-array, add the new item
}

如果您绝对必须创建具有该结构的数组,您可以稍微调整上面的代码以搜索您的数组并找到具有正确类型的子数组。但是,这似乎有点复杂。

这是在输出中获取确切数组结构的方法。这比我想象的要棘手:

//first build groups by type
$groups = array();

foreach($arr as $key => $array){
    //$type is not necessary, it's just for clarity below
    $type = $array['type'];

    if( !isset($groups[$type]) ){
        $groups[$type] = array();
        $groups[$type]['type'] = $array['type'];
    }
    $groups[$type][$array['name']] = $array['cost'];

}
//then combine the groups into a master array
$out = array();
foreach($groups as $g){
    $out[] = $g;
}
echo '<pre>'. print_r($out, true).'</pre>';

如果有人需要更通用的方法并且必须处理同一列中的多个值,我会稍微放大@larsAnders 解决方案。

用法(获得所需的确切输出):

$pivot_fruits = arr_pivot($arr, 'type', 'name', 'cost', 'sum', false, false); 

函数:

function arr_pivot(
    $arr,
    $arr_key_to_pivot_for_rows,
    $arr_key_to_pivot_for_columns,
    $arr_key_to_pivot_for_values,
    $grouping_method = "sum",
    $add_missing_columns=true,
    $sort_columns=true){

    if(!is_array($arr)) return false;

    $pivot_row = $arr_key_to_pivot_for_rows;
    $pivot_col = $arr_key_to_pivot_for_columns;
    $pivot_val = $arr_key_to_pivot_for_values;

    //first build groups by $col_name_to_pivot_for_rows
    $row_groups = [];
    $columns=[];
    foreach ($arr as $row_key => $row) {
        $group_label = $row[$pivot_row];
        $col_label = $row[$pivot_col];
        $value = $row[$pivot_val];
        if( !isset($row_groups[$group_label]) ){
            $row_groups[$group_label]=[];
            $row_groups[$group_label][$pivot_row] = $group_label;
        }
        if(!isset($columns[$col_label])) $columns[$col_label]=[];
        $row_groups[$group_label][$col_label][]=$value;
    }

    //then combine the groups into a return array
    $arr_pivoted = [];
    foreach($row_groups as $row_group){

        //all columns except of the first one are pivoted columns. split into the row name and the columns itself
        $row_group_columns = $row_group;
        $row_group_row = array_shift($row_group_columns);

        //ensure that all groups have all columns
        if($add_missing_columns) $row_group_columns = array_merge($columns,$row_group_columns);
        if($sort_columns) ksort($row_group_columns);

        $row_group_columns_grouped=[];

        //apply grouping function to columns
        foreach ($row_group_columns as $column_name => $row_group_column){
            $acount=count($row_group_column);
            switch ($grouping_method){
                default:
                case 'sum':
                    $row_group_columns_grouped[$column_name] = array_sum($row_group_column);
                    break;
                case 'avg':
                    $row_group_columns_grouped[$column_name] = $acount == 0 ? 0 : array_sum($row_group_column) / count($row_group_column);
                    break;
                case 'count':
                    $row_group_columns_grouped[$column_name] = count($row_group_column);
                    break;
                case 'max':
                    $row_group_columns_grouped[$column_name] = $acount == 0 ? 0 : max($row_group_column);
                    break;
                case 'min':
                    $row_group_columns_grouped[$column_name] = $acount == 0 ? 0 : min($row_group_column);
                    break;
                case 'concat':
                case 'implode':
                    $row_group_columns_grouped[$column_name] = implode(',',$row_group_column);
                    break;
            }
        }
        $arr_pivoted[] = array_merge([$pivot_row=>$row_group_row],$row_group_columns_grouped);
    }
    return $arr_pivoted;
}

PHP文档:

/**
 * Turns 2 dimensional array in a pivoted version
 *
 * @param array     $arr                            2 dimensional to pivot
 * @param string    $arr_key_to_pivot_for_rows      input array key to use as rows
 * @param string    $arr_key_to_pivot_for_columns   input array key to use as columns
 * @param string    $arr_key_to_pivot_for_values    input array key to use as values
 * @param string    $grouping_method                method to use on values out of sum|count|avg|min|max|concat. If values are not numeric use count or concat
 * @param bool      $add_missing_columns            if true all occurring columns in any row are added if missing
 * @param bool      $sort_columns                   if true all columns will be sorted by column name (=key)
 * @return array|bool                               false if input is not an array otherwise the pivoted result as 2 dimensional array
 */

如果有人有改进编码风格的冲动,输入验证and/or变量命名我会很高兴。

这个任务就像使用临时一级键对相关数据进行分组一样简单。

$array = [
    ['type' => 'fruit', 'name' => 'apple', 'cost' => 1],
    ['type' => 'fruit', 'name' => 'orange', 'cost' => 2],
    ['type' => 'vegetable', 'name' => 'carrot', 'cost' => 2.5],
    ['type' => 'vegetable', 'name' => 'avocado', 'cost' => 3.5]
];
$result = [];
foreach ($array as $row) {
    $result[$row['type']]['type'] = $row['type'];
    $result[$row['type']][$row['name']] = $row['cost'];
}
var_export(array_values($result));

与本页其他答案所展示的相反,在分配子元素之前,父元素不需要 instantiated/declared。 (在对象中分配子属性时不能这样说。)此基本任务也不需要条件或多个循环。

输出:

array (
  0 => 
  array (
    'type' => 'fruit',
    'apple' => 1,
    'orange' => 2,
  ),
  1 => 
  array (
    'type' => 'vegetable',
    'carrot' => 2.5,
    'avocado' => 3.5,
  ),
)

您还可以滥用 body-less foreach() 循环的解构语法来执行枢轴。 (Demo)

$array = [
    ['type' => 'fruit', 'name' => 'apple', 'cost' => 1],
    ['type' => 'fruit', 'name' => 'orange', 'cost' => 2],
    ['type' => 'vegetable', 'name' => 'carrot', 'cost' => 2.5],
    ['type' => 'vegetable', 'name' => 'avocado', 'cost' => 3.5]
];
$result = [];
foreach ($array as ['type' => $type, 'type' => $result[$type]['type'], 'name' => $name, 'cost' => $result[$type][$name]]);
var_export(array_values($result));

这提供了与上面相同的结果。请注意 type 密钥在解构时是如何被写入两次的——它看起来无效,但实际上有效。