如何将一个3级多维数组转换为2级数组并减少其维度?

4

I have an array of products like this:

$rows = [
    100 => [
        ['product_id' => 101, 'name' => ''],
        ['product_id' => 102, 'name' => ''],
        ['product_id' => 103, 'name' => ''],
    ],
    200 => [
        ['product_id' => 201, 'name' => ''],
        ['product_id' => 202, 'name' => ''],
    ],
    300 => [
        ['product_id' => 301, 'name' => ''],
        ['product_id' => 302, 'name' => ''],
        ['product_id' => 303, 'name' => ''],
        ['product_id' => 304, 'name' => ''],
    ]
];

我希望将它转换为这种结构,去掉一个层级:

$rows = [
    ['product_id' => 101, 'name' => ''],  //1st from 100 subArray
    ['product_id' => 201, 'name' => ''],  //1st from 200 subArray
    ['product_id' => 301, 'name' => ''],  //1st from 300 subArray
    ['product_id' => 102, 'name' => ''],  //2nd from 100 subArray
    ['product_id' => 202, 'name' => ''],  //etc...
    ['product_id' => 302, 'name' => ''],
    ['product_id' => 103, 'name' => ''],
    ['product_id' => 303, 'name' => ''],
    ['product_id' => 304, 'name' => ''],
];

我现在正在尝试使用以下代码实现这个功能:

$max_store_products = max(array_map('count', $rows));
$sortedArray = array();

for($j = 0; $j < $max_store_products; $j++)
{
    foreach($rows as $store_id => $store_products)
    {
        $sp = $rows[$store_id][$j];  

        if(isset($sp))
        {
            $sortedArray[] = $rows[$store_id][$j]; 
        }  
        else
            unset($rows[$store_id]);

    }
}

但这样做很费时间,并且也没有给我期望的输出结果。是否有更简单的方法?
4个回答

3

一句话概括

这个解决方案不依赖于数组值的唯一性和可排序性。它将通过总是从每个数组中取出一个元素来合并所有数组。

$result = array_filter(array_reduce(array_map(null, ...$rows), 'array_merge' ,[]));

var_dump($rows);

解释

让我们来分解一下:

$columns = array_map(null, ...$rows);

当您将null作为array_map的第一个参数传递时,它的行为与以下相同:
$columns = array_map(function (...$vals) {
    return $vals;
}, ...$rows);

这基本上是将$rows转置,因此您可以获得每个部分的第一个、第二个、第三个等元素的数组数组。传递null而不是回调可能看起来很奇怪,但实际上它并不像在文档中描述的那样是一个hack。
$rawResult = array_reduce($columns, 'array_merge', []);

在这里,您只需将所有列合并为一个数组。

$result = array_filter($rawResult);
array_filter会删除任何NULL条目,以防您的内部数组长度不均匀。

旧解决方案:先合并,后排序

假设您的值有可排序的内容,例如您示例中的product_id,您可以先合并数组,然后对结果进行排序:
$result = array_merge(...$rows);

usort($result, function ($a, $b) {
    return $a['product_id'] % 100 - $b['product_id'] % 100 ?: $a['product_id'] - $b['product_id'];
});

var_dump($result); // merged & sorted result

我认为你没有完全理解我的观点。 $result = array_merge(...$rows); 是有用的,而且我很快就能解决这个问题。 - Zia
1
好的,那我错过了什么?我以为你只想合并数组并按特定方式排序结果。 - Kuba Birecki
我实际上想出了一个很酷的一行代码,它不依赖于对项目进行排序的能力。如果你觉得有趣的话。 - Kuba Birecki
@KubaBirecki 有趣的一行代码解决方案,解释得很好!从你的回答中使用的新回答风格和词汇表来看,我猜你也读了我的回答 ;) - Rizier123
1
@Rizier123 这不是我第一次读到你的回答了 :) 你的一些回答真的很有启发性。我也喜欢你的解决方案,这让我尝试将其推向更高层次。 - Kuba Birecki

2

说明

我们拿一个简单的数组来解释:

Array(
    0 => Array(1, 4, 7),
    1 => Array(2, 5, 8),
    2 => Array(3, 6, 9),
)

首先,我们使用array_shift()函数将一个匿名函数添加到您的数组中,这样您的数组就变成了这样:

Array(
    0 => function(){...}

    //Your values
    1 => Array(1, 4, 7),
    2 => Array(2, 5, 8),
    3 => Array(3, 6, 9),
)

然后我们调用call_user_func_array()并将array_map()应用为回调函数。这样做的基本作用是:
//↓ 'array_map()' callback from 'call_user_func_array()'
array_map(function(){
    //Callback from the First array element

//        Second          Third           Fourth
//     array element   array element   array element   more elements...
//          ↓               ↓               ↓           ↓
}, Array(1, 4, 7), Array(2, 5, 8), Array(3, 6, 9) /* , ... */);

Array(1, 4, 7), Array(2, 5, 8), Array(3, 6, 9) /* , ... */
      │  │  │         │  │  │         │  │  └─ 3 iteration in 'array_map()' | 3 value
      │  │  │         │  │  │         │  └──── 2 iteration in 'array_map()' | 3 value
      │  │  │         │  │  │         └─────── 1 iteration in 'array_map()' | 3 value
      │  │  │         │  │  │
      │  │  │         │  │  └───────────────── 3 iteration in 'array_map()' | 2 value
      │  │  │         │  └──────────────────── 2 iteration in 'array_map()' | 2 value
      │  │  │         └─────────────────────── 1 iteration in 'array_map()' | 2 value
      │  │  │
      │  │  └───────────────────────────────── 3 iteration in 'array_map()' | 1 value
      │  └──────────────────────────────────── 2 iteration in 'array_map()' | 1 value
      └─────────────────────────────────────── 1 iteration in 'array_map()' | 1 value

Now this means we are going to loop through all subArrays at once, value by value and apply that anonymous function to all values which we loop through. In the anonymous function itself we basically just array_merge() the values which we got in the current iteration to the result array:

$result = array_merge($result, Array(1, 2, 3));  //First values from each subArray
$result = array_merge($result, Array(4, 5, 6));  //Second values from each subArray
$result = array_merge($result, Array(7, 8, 9));  //Third values from each subArray
//...

Code

<?php

    $arr = []; //Your array here
    $result = [];
    array_unshift($arr, function(...$values)use(&$result){
        $result = array_merge($result, array_filter($values));
    });

    call_user_func_array("array_map", $arr);

    print_r($result);

?>


0

我相当确定这就是你想要的:

<?php

$result = [];
// Get the highest number of items in an entry of `$rows`
$maxItems = 0;
foreach($rows as $row) {
   if (count($row)>$maxItems) $maxItems = $row;
}

for($ii=0; $ii < $maxItems; $ii++) {

   foreach($rows as $row) {

     if (isset($row[$ii])) {
       $result[] = $row[ii];
     }

   }

}

?>

你的版本失败的原因是,你有这行代码:

if(isset($sp))

然而,$sp 在那里总是被定义的。PHP没有像javascript一样的undefined类型,因此一旦你从数组中取出一个项目(无论它是否存在),它就被定义了,会抛出一个E_NOTICE并导致null。在PHP中,你应该真正提高错误消息的输出,因为这是显而易见的。

现在关于速度,你不能做太多来改善它。你可以:

  1. 删除第一个循环以获取计数,并将其与第二个循环结合起来,但我怀疑除非循环实际上非常大,否则这不会有太大的差异。
  2. 如果内存是你的主要瓶颈,你可以尝试切换到使用生成器的方法。从CPU的角度来看,这会稍微慢一些,但如果你的源数据绝对庞大,而你的PHP脚本导致服务器交换以应对,那么基于流和生成器的方法可能会给你更好的性能。

无论如何,如果你认真考虑为什么要这样做,并且是否有更明智的方法来解决这个问题而不仅仅是修复你的循环,那么可能会更好。如果你真的因为处理大量数据而导致性能不佳,那么应用程序设计可能需要修复,而不是这个循环。


-1

使用,

function array_flatten($array) { 
 if (!is_array($array)) { 
  return FALSE; 
 } 
 $result = array(); 
 foreach ($array as $key => $value) { 
  if (is_array($value)) { 
   $result = array_merge($result, array_flatten($value)); 
  } 
  else { 
   $result[$key] = $value; 
  } 
 } 
 return $result; 
} 

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