Search code examples
phparrayslaravelrecursionmultidimensional-array

Reduce a multidimensional array of unknown depth to an indexed array with associative rows


I have a multidimensional array with indeterminant depth and need to reduce it to a 2d array (an indexed array of associative rows).

array:5 [▼
  0 => array:3 [▼
    "id" => 2
    "level" => 0
    "email" => "bexcailimited1@gmail.com"
  ]
  1 => array:2 [▼
    0 => array:3 [▼
      "id" => 4
      "level" => 1
      "email" => "bexcailimited3@gmail.com"
    ]
    1 => array:2 [▼
      0 => array:3 [▼
        "id" => 5
        "level" => 2
        "email" => "bexcailimited4@gmail.com"
      ]
      1 => array:1 [▼
        0 => array:3 [▼
          "id" => 6
          "level" => 3
          "email" => "bexcailimited5@gmail.com"
        ]
      ]
    ]
  ]
  2 => array:3 [▼
    "id" => 3
    "level" => 0
    "email" => "bexcailimited2@gmail.com"
  ]
  4 => array:3 [▼
    "id" => 7
    "level" => 0
    "email" => "bexcaitest@gmail.com"
  ]
  5 => array:2 [▼
    0 => array:3 [▼
      "id" => 8
      "level" => 1
      "email" => "Test012@gmail.com"
    ]
    1 => array:2 [▼
      0 => array:3 [▼
        "id" => 9
        "level" => 2
        "email" => "test03@gmail.com"
      ]
      1 => array:2 [▼
        0 => array:3 [▼
          "id" => 10
          "level" => 3
          "email" => "test04@gmail.com"
        ]
        1 => array:2 [▼
          0 => array:3 [▼
            "id" => 11
            "level" => 4
            "email" => "test05@gmail.com"
          ]
          1 => array:1 [▼
            0 => array:3 [▼
              "id" => 12
              "level" => 5
              "email" => "test06@gmail.com"
            ]
          ]
        ]
      ]
    ]
  ]
]

I want to clean above array and get a 2d array like below (truncated):

array:3 [▼
  0 => array:3 [▼
    "id" => 1
    "level" => 2
    "email" => "example@example.com"
  ]
  1 => array:3 [▼
    "id" => 2
    "level" => 5
    "email" => "example@example2.com"
  ]
  2 => array:3 [▼
    "id" => 1
    "level" => 8
    "email" => "example@example3.com"
  ],
  ...
]

Ideally, I'd like the result to be ordered by id.

My project is running on Laravel8, if it matters.


Solution

  • To ensure that your associative subarrays are not deconstructed while flattening, only spread arrays which are not indexed. Wrap $row inside of a parent array so that when it is spread by ..., the original row of data is kept intact.

    Sort the structure after it is reduced to 2 levels.

    Code: (Demo)

    function flattenList(array $array): array
    {
        $result = [];
        foreach ($array as $row) {
            array_push($result, ...array_is_list($row) ? flattenList($row) : [$row]);
        }
        return $result;
    }
    
    $flatten2d = flattenlist($array);
    usort($flatten2d, fn($a, $b) => $a['id'] <=> $b['id']);
    var_export($flatten2d);