Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep array rows where a column value is found in a second flat array

I have an array, $arr1 with 5 columns as such:

 key    id  name    style   age whim
 0      14  bob     big     33  no
 1      72  jill    big     22  yes
 2      39  sue     yes     111 yes
 3      994 lucy    small   23  no
 4      15  sis     med     24  no
 5      16  maj     med     87  yes
 6      879 Ike     larg    56  no
 7      286 Jed     big     23  yes

This array is in a cache, not a database.

I then have a second array with a list of id values -

$arr2 = array(0=>14, 1=>72, 2=>8790)

How do I filter $arr1 so it returns only the rows with the id values in $arr2?

I have tried to use filter function (below), array_search, and several others but cannot figure out how to make it work.

$resultingArray = [];  // create an empty array to hold rows
$filter_function = function ($row) use ($arr2) {
    foreach ($arr2 as $arr) {
        return ($row['id'] == $arr);
    }
}
like image 531
ian Avatar asked Jan 19 '26 15:01

ian


2 Answers

This whole task can be accomplished with just one slick, native function call -- array_uintersect().

Because the two compared parameters in the custom callback may come either input array, try to access from the id column and if there isn't one declared, then fallback to the parameter's value.

Under the hood, this function performs sorting while evaluating as a means to improve execution time / processing speed. I expect this approach to outperform iterated calls of in_array() purely from a point of minimized function calls.

Code: (Demo)

var_export(
    array_uintersect(
        $arr1,
        $arr2,
        fn($a, $b) =>
            ($a['id'] ?? $a)
            <=>
            ($b['id'] ?? $b)
    )
);
like image 132
mickmackusa Avatar answered Jan 22 '26 05:01

mickmackusa


Something like this should do it, provided I've understood your question and data structure correctly:

$dataArray = [
  [ 'key' => 0, 'id' => 14  , 'name' => 'bob'  , 'style' => 'big'   , 'age' => 33  , 'whim' => 'no'  ],
  [ 'key' => 1, 'id' => 72  , 'name' => 'jill' , 'style' => 'big'   , 'age' => 22  , 'whim' => 'yes' ],
  [ 'key' => 2, 'id' => 39  , 'name' => 'sue'  , 'style' => 'yes'   , 'age' => 111 , 'whim' => 'yes' ],
  [ 'key' => 3, 'id' => 994 , 'name' => 'lucy' , 'style' => 'small' , 'age' => 23  , 'whim' => 'no'  ],
  [ 'key' => 4, 'id' => 15  , 'name' => 'sis'  , 'style' => 'med'   , 'age' => 24  , 'whim' => 'no'  ],
  [ 'key' => 5, 'id' => 16  , 'name' => 'maj'  , 'style' => 'med'   , 'age' => 87  , 'whim' => 'yes' ],
  [ 'key' => 6, 'id' => 879 , 'name' => 'Ike'  , 'style' => 'larg'  , 'age' => 56  , 'whim' => 'no'  ],
  [ 'key' => 7, 'id' => 286 , 'name' => 'Jed'  , 'style' => 'big'   , 'age' => 23  , 'whim' => 'yes' ]
];

$filterArray = [14, 72, 879];
$resultArray = array_filter( $dataArray, function( $row ) use ( $filterArray ) {
  return in_array( $row[ 'id' ], $filterArray );
} );

View this example on eval.in


However, your question appears to suggest this data might be coming from a database; is that correct? If so, perhaps it's more efficient to pre-filter the results at the database-level. Either by adding a field in the SELECT query, that represents a boolean value whether a row matched your filter ids, or by simply not returning the other rows at all.

like image 34
Decent Dabbler Avatar answered Jan 22 '26 04:01

Decent Dabbler



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!