如何将3级多维数组转置并还原成2级数组?[重复]

问题描述 投票:4回答:5

我有一个这样的产品阵列。

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

    }
}

但这需要很长的时间 而且也没有得到我想要的结果

有什么更简单的方法吗?

php arrays multidimensional-array transpose
5个回答
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

现在这意味着我们将一次循环浏览所有的子数组,一个一个的值 然后将匿名函数应用到我们循环浏览的所有值上。在匿名函数本身,我们基本上只是 array_merge() 将当前迭代中得到的值存入结果数组。

$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
//...

代码

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

?>

2
投票

单行本

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

$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 而不是回调,可能看起来很奇怪,但实际上这并不是一个黑客,因为它的描述是在 文件.

$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

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没有一个 undefined 类型,就像javascript一样,所以一旦你从一个数组中取出一个项目(不管它是否存在),它被定义了,就会抛出一个 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; 
} 
© www.soinside.com 2019 - 2024. All rights reserved.