【问题标题】:How to combine two multi-dimensional arrays based on key value pairs without nested foreach loop?如何在没有嵌套foreach循环的情况下基于键值对组合两个多维数组?
【发布时间】:2019-03-31 09:43:14
【问题描述】:

我有 2 个数组,$fileArr$noteArr

$fileArr 是一个文件列表。一个文件可以链接到多个故事。所以在这个$fileArr 中,你会看到我需要列出的每个故事的所有文件。请注意,CAR.jpg ([processId]=>111) 链接到 [storyId]=>1[storyId]=>2。所以 CAR.jpg 将被列出两次。

我想从$noteArr 中取出所有笔记,并通过匹配[processId 将它们放入$fileArr。所以 CAR.jpg 的每个实例都有 2 个音符,而 TRUCK.jpg 没有。

我当前的 $fileArr

Array
(
[0] => Array
    (
        [fileName] => CAR.jpg
        [processId] => 111
        [storyId] => 1
    )

[1] => Array
    (
        [fileName] => CAR.jpg
        [processId] => 111
        [storyId] => 2
    )

[2] => Array
    (
        [fileName] => TRUCK.jpg
        [processId] => 222
        [storyId] => 3
    )
)

我现在的 $noteArr

Array
(
[0] => Array
    (
        [noteId] => 50
        [note] => this is a note
        [processId] => 111
    )

[1] => Array
    (
        [noteId] => 51
        [note] => and this is also a note
        [processId] => 111
    )

)

我想要的新数组,通过匹配 processId 放置在文件下的注释

Array
(
[0] => Array
    (
        [fileName] => CAR.jpg
        [processId] => 111
        [storyId] => 1
        [notes] => Array
              (
                    [50] => Array
                          (
                                [noteId] => 50
                                [note] => this is a note
                                [processId] => 111
                          )
                    [51] => Array
                          (
                                [noteId] => 51
                                [note] => and this is also a note
                                [processId] => 111
                          )
              )
    )

[1] => Array
    (
        [fileName] => CAR.jpg
        [processId] => 111
        [storyId] => 2
        [notes] => Array
              (
                    [50] => Array
                          (
                                [noteId] => 50
                                [note] => this is a note
                                [processId] => 111
                          )
                    [51] => Array
                          (
                                [noteId] => 51
                                [note] => and this is also a note
                                [processId] => 111
                          )
              )
    )

[2] => Array
    (
        [fileName] => TRUCK.jpg
        [processId] => 222
        [storyId] => 3
    )
)

我可以通过我在下面编写的代码完成此操作,但不想在循环中使用循环。还有其他方法可以实现吗?

我当前的代码(循环内循环)

$newArr = array();

$i = 0;
foreach($fileArr as $file){
    $newArr[$i] = $file;

    if(count($noteArr)>0){
        foreach($noteArr as $note){
            if($file['processId']==$note['processId']){
                $newArr[$i]['notes'][$note['id']] = $note;
            }
        }
    }
    $i++;
}

【问题讨论】:

  • 问题,你为什么不想使用嵌套循环?
  • 嗨@Difster,有人告诉我,由于复杂性和陷入永无止境的循环的可能性,在必要时应避免嵌套循环。我知道有时需要它们,但如果有一个实例我可以使用另一种解决方案,我通常会走这条路。您认为这是必要的情况吗?
  • @jmchauv 您不应该陷入使用 foreach 的永无止境的循环中,因为它只是从第一个元素迭代到最后一个元素。

标签: php arrays loops multidimensional-array foreach


【解决方案1】:

如果你想去掉嵌套循环以减少执行时间,你可以通过两遍来完成

// save items of noteArr for each processId
$temp = [];
foreach($noteArr as $k => $note) {
   $temp[$note['processId']][] = $note;
}

// and add saved sub-arrays to the source one
$newArr = [];
$i = 0;
foreach($fileArr as $file){
    $newArr[$i] = $file;
    if(isset($temp[$file['processId']])) 
         $newArr[$i]['notes'] = $temp[$file['processId'];
    $i++;
}

【讨论】:

    【解决方案2】:

    没有嵌套循环,你可以创建一个函数并通过引用传递:

    function addNote(array &$array, array $notes)
    {
        $array['notes'] = [];
        foreach ($notes as $note)
        {
            if ($note['processId'] == $array['processId']) {
                $array['notes'][] = $note;
            }
        }
        return $array;
    }
    
    foreach ($fileArr as &$file) {
        addNote($file, $notes);
    }
    
    var_dump($fileArr);
    

    看到它在这里工作https://3v4l.org/u37UL

    【讨论】:

    • 当然这只是一个嵌套循环,但在函数内部有 1 个循环?!
    • 是的,这仍然是一个嵌套循环,只是提取到另一个方法中。
    【解决方案3】:

    您好,我快速浏览一下我将如何解决您的问题。不幸的是,它以嵌套循环结束,但我不需要循环任何项目(在您的解决方案中,您循环每个文件的所有注释)两次。

    function sortProcessId($a, $b)
    {
        return $a['processId'] <=> $b['processId'];
    }
    
    $newArr = [];
    
    usort($fileArr, 'sortProcessId');
    usort($noteArr, 'sortProcessId');
    rsort($noteArr);
    $currentProcessId = 0;
    $currentNote = array_pop($noteArr);
    $newArr = [];
    foreach ($fileArr as $key => $file){
        $newArr[$key] = $file;
        if ($currentProcessId === $file['processId']) {
            $newArr[$key]['notes'] = [ $newArr[--$key]['notes']];
            continue;
        }
        $newArr[$key]['notes'] = [];
        $currentProcessId = $file['processId'];
        while ($file['processId'] == $currentNote['processId']) {
            $newArr[$key]['notes'][$currentNote['noteId']] = $currentNote;
            $currentNote = array_pop($noteArr);
        }
    }
    var_dump($newArr);
    

    补充说明: 我使用 rsort 来使用 array_pop,它应该比 array_shift 更快

    【讨论】:

      【解决方案4】:

      您可以在 PHP 中使用一堆数组函数。

      array_walk($fileArr, function(&$item) use ($noteArr) {
        $processId = $item['processId'];
        $foundNotes = array_filter($noteArr, function($note) use ($processId) {
          return $note['processId'] === $processId;
        });
      
        if (!empty($foundNotes)) {
          $item['notes'] = $foundNotes;
        }
      });
      

      这将改变你的$fileArr 成为我认为你想要的。

      FWIW 我不认为嵌套循环是一种不好的做法。虽然这段代码以您提出的方式解决了问题,但我认为它更难理解。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-03
        • 2022-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-24
        相关资源
        最近更新 更多