从多维数组中按值合并subArray值

时间:2016-05-03 11:23:00

标签: php arrays multidimensional-array

我有一系列这样的产品:

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

我想这样排序:

$rows[] = array(
            array('product_id' => 101, 'name' => ''),  //First value from first subArray
            array('product_id' => 201, 'name' => ''),  //First value from second subArray
            array('product_id' => 301, 'name' => ''),  //First value from third subArray
            array('product_id' => 102, 'name' => ''),  //Second value from first subArray
            array('product_id' => 202, 'name' => ''),  //...
            array('product_id' => 302, 'name' => ''),
            array('product_id' => 103, 'name' => ''),
            array('product_id' => 303, 'name' => ''),
            array('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 个答案:

答案 0 :(得分: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

现在这意味着我们将一次循环遍历所有subArrays,逐个值并将该匿名函数应用于我们循环的所有值。在匿名函数本身,我们基本上只是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);

?>

答案 1 :(得分:2)

The One-liner

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

$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而不是回调可能看起来很奇怪,但它实际上并不像docs中描述的那样。

$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

答案 2 :(得分: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并导致{ {1}}。您应该在PHP中加快错误消息传递,因为这很明显。

就速度而言,你可以做很多事情来改善这一点。你可以:

  1. 删除第一个循环以获取计数并将其与第二个循环组合,但我怀疑这会产生很大的不同,除非循环实际上很大。
  2. 如果内存是您的主要瓶颈,您可以尝试切换到使用生成器的方法。从CPU的角度来看,这会慢一点,但是如果您的源数据非常庞大并且您的PHP脚本导致服务器交换以应对,那么基于流,基于生成器的方法可能会为您提供更好的性能。
  3. 如果您首先考虑为什么要这样做,并且如果有更好的方法来解决这个问题而不仅仅修复您的循环,那么可能会更好。如果你真的因此而得到不好的表现,因为你需要处理大量的数据,应用程序设计可能需要修复,而不是这个循环。

答案 3 :(得分:-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; 
}