Filter array rows by matching one or more key-value pairs in associative array
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.
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.
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,
),
)