1

I have an multidimensional array and i'd like to filter by many values.

$datas = [
    [
        'id' => 2135,
        'first_name' => 'John',
        'last_name' => 'Doe',
        'gender' => 'male'
    ],
    [
        'id' => 3245,
        'first_name' => 'Sally',
        'last_name' => 'Smith',
        'gender' => 'female'
    ],
    [
        'id' => 5342,
        'first_name' => 'Jane',
        'last_name' => 'Doe',
        'gender' => 'female'
    ],
    [
        'id' => 5623,
        'first_name' => 'Peter',
        'last_name' => 'Doe',
        'gender' => 'male'
    ],
    [
        'id' => 7216,
        'first_name' => 'Mike',
        'last_name' => 'Lill',
        'gender' => 'male'
    ]
];

I have combined the methods of array_filter and array_search and got a good result but this only does the filtering of only one value. I'd like something like this...

array_filter(
    $datas,
    function ($key) {
        return array_search(['Doe', 'male'...], $key);
});

And its give

array(
    array(
        'id' => 2135,
        'first_name' => 'John',
        'last_name' => 'Doe',
        'gender' => 'male'
    ),
    array(
        'id' => 5623,
        'first_name' => 'Peter',
        'last_name' => 'Doe',
        'gender' => 'male'
    )
)
0

2 Answers 2

5

Of course you can simply loop any given input and check if a given element matches any criteria you implement:

<?php
$input = [
    [
        'id' => 2135,
        'first_name' => 'John',
        'last_name' => 'Doe',
        'gender' => 'male'
    ],
    [
        'id' => 3245,
        'first_name' => 'Sally',
        'last_name' => 'Smith',
        'gender' => 'female'
    ],
    [
        'id' => 5342,
        'first_name' => 'Jane',
        'last_name' => 'Doe',
        'gender' => 'female'
    ],
    [
        'id' => 5623,
        'first_name' => 'Peter',
        'last_name' => 'Doe',
        'gender' => 'male'
    ],
    [
        'id' => 7216,
        'first_name' => 'Mike',
        'last_name' => 'Lill',
        'gender' => 'male'
    ]
];

$needles = ['Doe', 'male'];
$output = [];
array_walk($input, function($element) use ($needles, &$output) {
    $matches = true;
    foreach ($needles as $needle) {
        if (!in_array($needle, $element)) {
            $matches = false;
        }
    }
    if ($matches) {
        $output[] = $element;
    }
});

print_r($output);

The obvious output is:

Array
(
    [0] => Array
        (
            [id] => 2135
            [first_name] => John
            [last_name] => Doe
            [gender] => male
        )

    [1] => Array
        (
            [id] => 5623
            [first_name] => Peter
            [last_name] => Doe
            [gender] => male
        )

)
Sign up to request clarification or add additional context in comments.

Comments

3

You wish to filter your multidimensional array based on multiple qualifying values irrespective of their keys.

If $datas is coming from a database, you should be performing this filtration in your sql to avoid needlessly squandering resources.

If you must filter in php, then array_filter() is an intuitive and logical function to call upon.

Code: (Demo)

$needles = ['Doe', 'male'];

var_export(
    array_filter($datas, function($row) use ($needles) {
        return !array_diff($needles, $row);
    })
);

array_filter() processes a boolean value in each return as it iterates the rows. array_intersect($needles, $row) will only keep the $needles elements which are present in the current row. If the original $needles contains the same data as the filtered $needles then return true (keep the row).

From PHP7.4 and higher, you can use arrow syntax:

var_export(
    array_filter($datas, fn($row) => !array_diff($needles, $row)
);

Output: (from either snippet)

array (
  0 => 
  array (
    'id' => 2135,
    'first_name' => 'John',
    'last_name' => 'Doe',
    'gender' => 'male',
  ),
  3 => 
  array (
    'id' => 5623,
    'first_name' => 'Peter',
    'last_name' => 'Doe',
    'gender' => 'male',
  ),
)

Note that the original first-level keys are preserved. If your project requires the multidimensional array to be reindexed, write the array_filter() call inside of array_values().


If you'd like some other techniques for the sake of running your own benchmarks with your own data, these language constructs will also provide filtration: (Demo)

foreach ($datas as $row) {
    if (!array_diff($needles, $row)) { // all needles found
        $result[] = $row;
    }
}
var_export($result);  // reindexed already

and

foreach ($datas as $index => $row) {
    if (array_diff($needles, $row)) { // one or more needles not found
        unset($datas[$index]);
    }
}
var_export($datas);

For best efficiency, implement a nested loop with in_array() calls. It may seem counterintuitive to make so many iterated function calls, but the conditional continue allows the time complexity to be optimized and therefore delivers a better "little o" because it can stop iterating as soon as a needle is not found.

Code: (Demo) (array_filter() Demo)

foreach ($datas as $row) {
    foreach ($needles as $needle) {
        if (!in_array($needle, $row)) {
            continue 2;
        }
    }
    $result[] = $row;
}
var_export($result);

I should also point to this related page (which has an unfortunately vague problem statement). I do not endorse a few of the techniques there (including the accepted answer), but there is certainly a technical relationship between these two pages.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.