Alex
Alex

Reputation: 2299

Filtering arrays based on the value of a key inside of that array in PHP

I have a ton of parsed XML records that are related by two attributes: id and rid.

These XML records, when parsed, create the following (example) PHP array:

Array(
   'master' => array(
      [0] => array( 'id' => 123, 'info' => 'hello' ),
      [1] => array( 'id' => 456, 'info' => 'world' )
   ),
   'tbl-ex' => array(
      [0] => array( 'rid' => 123, 'test' => 'aye', 'num' => 88 ),
      [1] => array( 'rid' => 123, 'test' => 'bbb', 'num' => 99 ), 
      [2] => array( 'rid' => 456, 'test' => 'zzz', 'num' => 102, 'o' => 'h')
   ),
   'tbl-ey' => array(
      [0] => array( 'rid' => 456, 'mama' => 'mia' ),
      [1] => array( 'rid' => 123, 'oof' => 'foo' )
   ),
   'tbl-ez' => array(
      [0] => array( 'rid' => 123, 'stop' => 'wegetit', 'ok' => 1 ),
      [1] => array( 'rid' => 456, 'finally' => 'done' )
   )
);

When I parse this, I want all records under master to be returned on the condition that id == rid, in this format:

Array(
  [0] => array(
     'master' => array( 'id' => 123, 'info' => 'hello' ),
     'tbl-ex' => array( 
         [0] => array( 'test' => 'aye', 'num' => 88 ),
         [1] => array( 'test' => 'bbb', 'num' => 99 )
     ),
     'tbl-ey' => array(
         [0] => array( 'oof' => 'foo' )
     ),
     'tbl-ez' => array(
         [0] => array( 'stop' => 'wegetit', 'ok' => 1 )
      )
  ),
  [1] => array(
     'master' => array( 'id' => 456, 'info' => 'world' ),
     'tbl-ex' => array( 
         [0] => array( 'test' => 'zzz', 'num' => 102, 'o' => 'h' )
     ),
     'tbl-ey' => array(
         [0] => array( 'mama' => 'mia' )
     ),
     'tbl-ez' => array(
         [0] => array( 'finally' => 'done' )
      )
  )
);

This seems obvious (and works):

$ret = array();

$init_record = $original_array['master'];
$records_to_merge = $original_array;
unset($records_to_merge['master']);

$i = 0;
foreach($init_record as $master_index => $master){
   $current_id = $master['id']; 
   foreach($records_to_merge as $record_type => $record_array){
       foreach($record_array as $index => $record){
           if($current_id == $record['rid']){
              $ret[$i]['master'] = $master;
              $ret[$i][$record_type] = $record;
              $i++;
           }
       }
    }
}

This works, but since I have a ton of records (and a lot more data), it's excruciatingly slow.

I then tried to use an array_filter with a callback function that evaluates the $record, followed by the index rid being equal to the $master_id. This however filters out the matching record, and not the entire array it is contained in. So I just get a bunch of matching rid's in my array but no other data.

Is there some fast, easy way that I'm overlooking right now?

Upvotes: 1

Views: 51

Answers (1)

Tim Morton
Tim Morton

Reputation: 2644

Here's a solution that has only one nested foreach instead of two. I'm not sure if it will make a difference since every element of the array is iterated through. It makes one change in the structure of the new array: the outer array is associative instead of just indexed. The order should be preserved, though.

php > $original = array(
php (    'master' => array(
php (       array( 'id' => 123, 'info' => 'hello' ),
php (       array( 'id' => 456, 'info' => 'world' )
php (    ),
php (    'tbl-ex' => array(
php (       array( 'rid' => 123, 'test' => 'aye', 'num' => 88 ),
php (       array( 'rid' => 123, 'test' => 'bbb', 'num' => 99 ), 
php (       array( 'rid' => 456, 'test' => 'zzz', 'num' => 102, 'o' => 'h')
php (    ),
php (    'tbl-ey' => array(
php (       array( 'rid' => 456, 'mama' => 'mia' ),
php (       array( 'rid' => 123, 'oof' => 'foo' )
php (    ),
php (    'tbl-ez' => array(
php (       array( 'rid' => 123, 'stop' => 'wegetit', 'ok' => 1 ),
php (       array( 'rid' => 456, 'finally' => 'done' )
php (    )
php ( );
php > 
php > //$merge = $original;
php > //unset($merge['master']);
php > unset($pointer);
php > 
php > 
php > foreach($original as $tbl => $data) {
php {     
php {     foreach($data as $row) {
php {         if($tbl=='master') {
php {             $pointer[$row['id']]['master'] = $row;
php {             continue;
php {         }
php {         $pointer[$row['rid']][$tbl][] = $row;
php {         
php {     }
php {     
php { }
php > 
php > print_r($pointer);
Array
(
    [123] => Array
        (
            [master] => Array
                (
                    [id] => 123
                    [info] => hello
                )

            [tbl-ex] => Array
                (
                    [0] => Array
                        (
                            [rid] => 123
                            [test] => aye
                            [num] => 88
                        )

                    [1] => Array
                        (
                            [rid] => 123
                            [test] => bbb
                            [num] => 99
                        )

                )

            [tbl-ey] => Array
                (
                    [0] => Array
                        (
                            [rid] => 123
                            [oof] => foo
                        )

                )

            [tbl-ez] => Array
                (
                    [0] => Array
                        (
                            [rid] => 123
                            [stop] => wegetit
                            [ok] => 1
                        )

                )

        )

    [456] => Array
        (
            [master] => Array
                (
                    [id] => 456
                    [info] => world
                )

            [tbl-ex] => Array
                (
                    [0] => Array
                        (
                            [rid] => 456
                            [test] => zzz
                            [num] => 102
                            [o] => h
                        )

                )

            [tbl-ey] => Array
                (
                    [0] => Array
                        (
                            [rid] => 456
                            [mama] => mia
                        )

                )

            [tbl-ez] => Array
                (
                    [0] => Array
                        (
                            [rid] => 456
                            [finally] => done
                        )

                )

        )

)
php > 

Upvotes: 1

Related Questions