Ty W
Ty W

Reputation: 6814

most efficient method of turning multiple 1D arrays into columns of a 2D array

As I was writing a for loop earlier today, I thought that there must be a neater way of doing this... so I figured I'd ask. I looked briefly for a duplicate question but didn't see anything obvious.

The Problem:

Given N arrays of length M, turn them into a M-row by N-column 2D array

Example:

$id   = [1,5,2,8,6]
$name = [a,b,c,d,e]
$result = [[1,a],
           [5,b],
           [2,c],
           [8,d],
           [6,e]]

My Solution:

Pretty straight forward and probably not optimal, but it does work:

<?php
// $row is returned from a DB query
// $row['<var>'] is a comma separated string of values
$categories = array();
$ids = explode(",", $row['ids']);
$names = explode(",", $row['names']);
$titles = explode(",", $row['titles']);
for($i = 0; $i < count($ids); $i++) {
    $categories[] = array("id" => $ids[$i],
                          "name" => $names[$i],
                          "title" => $titles[$i]);
}
?>

note: I didn't put the name => value bit in the spec, but it'd be awesome if there was some way to keep that as well.

Upvotes: 1

Views: 490

Answers (2)

anomareh
anomareh

Reputation: 5584

Maybe this? Not sure if it's more efficient but it's definitely cleaner.

/*
Using the below data:

$row['ids'] = '1,2,3';
$row['names'] = 'a,b,c';
$row['titles'] = 'title1,title2,title3';
*/

$categories = array_map(NULL,
  explode(',', $row['ids']),
  explode(',', $row['names']),
  explode(',', $row['titles'])
);

// If you must retain keys then use instead:
$withKeys = array();

foreach ($row as $k => $v) {
    $v = explode(',', $v);

    foreach ($v as $k2 => $v2) {
        $withKeys[$k2][$k] = $v[$k2];
    }
}

print_r($categories);
print_r($withKeys);

/*
$categories:

array
  0 => 
    array
      0 => int 1
      1 => string 'a' (length=1)
      2 => string 'title1' (length=6)
...

$withKeys:

array
  0 =>
    array
      'ids' => int 1
      'names' => string 'a' (length=1)
      'titles' => string 'title1' (length=6)
...
*/

Just did a quick simple benchmark for the 4 results on this page and got the following:

// Using the following data set:
$row = array(
    'ids'       =>  '1,2,3,4,5',
    'names'     =>  'abc,def,ghi,jkl,mno',
    'titles'    =>  'pqrs,tuvw,xyzA,BCDE,FGHI'
);

/*
For 10,000 iterations,

Merge, for:
0.52803611755371

Merge, func:
0.94854116439819

Merge, array_map:
0.30260396003723

Merge, foreach:
0.40261697769165
*/

Upvotes: 3

Peter Bailey
Peter Bailey

Reputation: 105908

Yup, array_combine()

$result = array_combine( $id, $name );

EDIT

Here's how I'd handle your data transformation

function convertRow( $row )
{
  $length = null;
  $keys = array();

  foreach ( $row as $key => $value )
  {
    $row[$key] = explode( ',', $value );
    if ( !is_null( $length ) && $length != count( $row[$key] ) )
    {
      throw new Exception( 'Lengths don not match' );
    }
    $length = count( $row[$key] );

    // Cheap way to produce a singular - might break on some words
    $keys[$key] = preg_replace( "/s$/", '', $key );
  }

  $output = array();

  for ( $i = 0; $i < $length; $i++ )
  {
    foreach ( $keys as $key => $singular )
    {
      $output[$i][$singular] = $row[$key][$i];
    }
  }

  return $output;
}

And a test

$row = convertRow( $row );
echo '<pre>';
print_r( $row );

Upvotes: 1

Related Questions