Filter array rows by matching one or more key-value pairs in associative array

1.7k views Asked by At

Suppose,

$data = array(
   array('id' => 1, 'user_id' => 1, 'assignment_id' => 1, 'grade' => 90),
   array('id' => 2, 'user_id' => 3, 'assignment_id' => 2, 'grade' => 85),
   array('id' => 3, 'user_id' => 5, 'assignment_id' => 5, 'grade' => 66),
);

Now I want to filter the rows like following:

$rules = array(
    'user_id' => 5,
    'assignment_id' => 5
);

This should return the row at $data[2].

$rules = array(
    'user_id' => 3,
    'assignment_id' => 2,
    'grade' => 85
);

will return $data[1].

Here order of keys may be different both in $data elements and $rules.

I tried with array_intersect, but that is not working for me.

2

There are 2 answers

0
Mike Brant On BEST ANSWER

If you just need to return a list of of the elements in $data which match the filtering criteria, you can use a combination of array_filter() and array_intersect_assoc() to do the job:

// build an array of your filtering criteria
$filter_array = array(
   'user_id' => 3,
   'assignment_id' => 5
);

// filter the array
$filtered_array = array_filter($data, function ($val_array) use ($filter_array) {
    $intersection = array_intersect_assoc($val_array, $filter_array);
    return (count($intersection)) === count($filter_array);
});

Note that you need PHP >= 5.3.0 to utilize the anonymous function as shown.

0
mickmackusa On

Here is a more modern and elegant approach.

Use arrow function syntax to allow $rules into the custom function's scope. If after associatively filtering the rules array by each encountered row there are no remaining elements, then all rules were satisfied.

Code: (Demo)

$data = [
   ['id' => 1, 'user_id' => 1, 'assignment_id' => 1, 'grade' => 90],
   ['id' => 2, 'user_id' => 3, 'assignment_id' => 2, 'grade' => 85],
   ['id' => 3, 'user_id' => 5, 'assignment_id' => 5, 'grade' => 66],
];

$rules = ['user_id' => 3, 'assignment_id' => 2];

var_export(
    array_filter($data, fn($row) => !array_diff_assoc($rules, $row))
);

Output:

array (
  1 => 
  array (
    'id' => 2,
    'user_id' => 3,
    'assignment_id' => 2,
    'grade' => 85,
  ),
)