复杂合并技术:如何使用配置数组转置特定的数据集


Complex merge technique: How to transpose specific sets of data using a configuration array?

我整天都在为多维数组创建一个merge function。场景有点不同,很难用语言描述。相反,我将尝试用一个实际的例子来解释它。

$actual_array = [
     'assets' => [1, 2, 3],
     'liabilities' => [1, 2, 3, 4, 5, 6],
     'equity' => [1],
     'income' => [1, 2, 3, 4],
     'expenses' => [1, 2, 3]
];
$merge = [
    'balance_sheet' => ['assets', 'liabilities', 'equity'],
    'income' => ['income', 'expenses'],
];
self::merge( $merge, $actual_array );

该函数将合并指定的列,然后转置并填充结果。

public static function merge( array $merges, array $data )
{
    $bigger_array_length = 0;
    $arr = [];
    $columns = [];
    foreach ($merges as $key => $merge) {
        
        foreach ($merge as $index => $column) {
           //check which array has bigger length in the iteration
            if($bigger_array_length < count($data[$column]))
                $bigger_array_length = count($data[$column]);
            $columns[] = $column;
            
        }
        //when i die and dump the columns array on its first iterate
        dd($columns); // assets, liabilities, equity
        if($bigger_array_length> 0) {
            
            $total_columns = count($columns);// on first iteration 3 assets, liabilities and equity
            for($i = 0; $i < $bigger_array_length; $i++) {
                //
                $arr[$key][] = [ 
                        $columns[$total_columns - 1] => isset($data[ $columns[$total_columns - 1] ][$i]) ? $data[ $columns[$total_columns - 1] ][$i] : 0,
                        $columns[$total_columns - 2] => isset($data[ $columns[$total_columns - 2] ][$i]) ? $data[ $columns[$total_columns - 2] ][$i] : 0,
                        $columns[$total_columns - 3] => isset($data[ $columns[$total_columns - 3] ][$i]) ? $data[ $columns[$total_columns - 3] ][$i] : 0 
                    ]; 
            }
        }
      //when i die and dump on first iteration then it's just fine
    array:1 [▼
  "balance_sheet" => array:6 [▼
    0 => array:3 [▼
      "equity" => 1
      "liabilities" => 1
      "assets" => 1
    ]
    1 => array:3 [▼
      "equity" => 0
      "liabilities" => 2
      "assets" => 2
    ]
    2 => array:3 [▼
      "equity" => 0
      "liabilities" => 3
      "assets" => 3
    ]
    3 => array:3 [▼
      "equity" => 0
      "liabilities" => 4
      "assets" => 0
    ]
    4 => array:3 [▼
      "equity" => 0
      "liabilities" => 5
      "assets" => 0
    ]
    5 => array:3 [▼
      "equity" => 0
      "liabilities" => 6
      "assets" => 0
    ]
  ]
]
$columns = [];
      
    }
}

我只是被困在这里,不知道如何让它动态化。

[$total_columns - 1] // the 1, 2, 3 or so on
//something like [$total_columns - $i]

因此,如果我让 foreach 运行第二次迭代,那么它会输出undefined index error .

e.x [$total_columns - 3] 将在第二次迭代时-1 index,因为第二次迭代只有 2 total columns

这将导致Undefined offset: -1.

我想要实现的目标:

"balance_sheet" => array:6 [▼
0 => array:3 [▼
  "equity" => 1
  "liabilities" => 1
  "assets" => 1
]
1 => array:3 [▼
  "equity" => 0
  "liabilities" => 2
  "assets" => 2
]
2 => array:3 [▼
  "equity" => 0
  "liabilities" => 3
  "assets" => 3
]
3 => array:3 [▼
  "equity" => 0
  "liabilities" => 4
  "assets" => 0
]
4 => array:3 [▼
  "equity" => 0
  "liabilities" => 5
  "assets" => 0
]
5 => array:3 [▼
  "equity" => 0
  "liabilities" => 6
  "assets" => 0
]
],
"income" => array:4 [▼
    0 => array:2 [▼
      "expenses" => 1
      "income" => 1
    ]
    1 => array:2 [▼
      "expenses" => 2
      "income" => 2
    ]
    2 => array:2 [▼
      "expenses" => 3
      "income" => 3
    ]
    3 => array:2 [▼
      "expenses" => 0
      "income" => 4
    ]
  ]
]
function spec_merge($arr) {
   // find max length of array items
   $m = max(array_map(count, $arr));
   // fill array items to max length by 0
   $a = array_map(function($i) use($m) {
           return ($m - count($i)) ? 
                   $i + array_fill(count($i), $m - count($i), 0) :
                   $i; }, 
        $arr);
   // make array of sourse keys     
   $keys = array_keys($a);
   // transpose array
   array_unshift($a, null);
   $a = call_user_func_array("array_map", $a);
   // set correct keys
   $a = array_map(function ($i) use($keys) {
           return array_combine($keys, $i); }, 
        $a);
   return $a;  
}
$new = spec_merge([
     'assets' => [1, 2, 3],
     'liabilities' => [1, 2, 3, 4, 5, 6],
     'equity' => [1]
     ]);
print_r($new); 

结果

  [[
    [assets] => 1
    [liabilities] => 1
    [equity] => 1
  ][
    [assets] => 2
    [liabilities] => 2
    [equity] => 0
  ][            
    [assets] => 3
    [liabilities] => 3
    [equity] => 0
  ][
    [assets] => 0
    [liabilities] => 4
    [equity] => 0
  ][
    [assets] => 0
    [liabilities] => 5
    [equity] => 0
  ][
    [assets] => 0
    [liabilities] => 6
    [equity] => 0
  ]]

演示

我注意到发布的问题要求和接受的答案之间存在真正的脱节(它没有提供问题所要求的内容);所以我决定自己写。

  1. 循环访问 2 个"配置"组(balance_sheetincome )。
  2. 按当前组 ($inclusions) 中指定的键隔离数据行 ( $isolatedData )。
  3. 确定隔离数据中最长数组的长度($max)。
  4. $isolatedData中循环$max次,并使用新的关联转置结构将值存储在结果数组中。 如果值不可用,请使用空合并运算符 (??) 分配回退值 0

代码:(演示)

class Helper
{
    public static function populateCustomMatrices (array $data, array $conf): array
    {
        $result = [];
        foreach ($conf as $groupName => $inclusions) {
            $isolatedData = array_intersect_key($data, array_flip($inclusions));
            for ($i = 0, $max = max(array_map('count', $isolatedData)); $i < $max; ++$i) {
                foreach ($inclusions as $key) {
                    $result[$groupName][$i][$key] = $isolatedData[$key][$i] ?? 0;
                }
            }
        }
        return $result;
    }
}
$data = [
     'assets' => [1, 2, 3],
     'liabilities' => [1, 2, 3, 4, 5, 6],
     'equity' => [1],
     'income' => [1, 2, 3, 4],
     'expenses' => [1, 2, 3]
];
$conf = [
    'balance_sheet' => ['assets', 'liabilities', 'equity'],
    'income' => ['income', 'expenses'],
];
var_export(Helper::populateCustomMatrices($data, $conf));