Filter a 2d array by a static value and a column in another 2d array

s2j5cfk0  于 2022-10-22  发布在  PHP
关注(0)|答案(2)|浏览(168)

I have 2 arrays where they have some common id values, but the keys for these id keys differ slightly.

$comps = [
  [
    'c_id' => '123',
    'status' => 'active'
  ],
  [
    'c_id' => '456',
    'status' => 'destroyed'
  ],
  [
    'c_id' => '789',
    'status' => 'active'
  ]
];

$rests = [
  [
    'r_id' => 123,
    'extra' => 'some extra info for r_id 123'
  ],
  [
    'r_id' => 456,
    'extra' => 'some extra info for r_id 456'
  ]
];

My objective here is to return all entries of the $rests array that have corresponding entries within the $comps array that have both matching ID values and a status => active .
How can one achieve this?
I have seen and used array_uintersect() in the past, however I can't seem to get this to work in the desired way.

noj0wjuj

noj0wjuj1#

You can achive this with a nested foreach loop.

$matches = [];
foreach ($rests as $rest) {
    foreach ($comps as $comp) {
        if ($rest['r_id'] === $comp['c_id'] && $comp['status'] === 'active') {
            $matches[] = $rest;
        }
    }
}

print_r($matches);

Output

Array
(
    [0] => Array
        (
            [r_id] => 123
            [extra] => some extra info for r_id 123
        )

)
e0bqpujr

e0bqpujr2#

Here is the array_uintersect() implementation with the two rules.
This is a good choice because PHP optimizes the comparisons by using a sorting algorithm under the hood.
Code: ( Demo )

var_export(
    array_uintersect(
        $comps,
        $rests,
        fn($a, $b) =>
            [$a['c_id'] ?? $a['r_id'], ($a['status'] ?? 'active') === 'active']
            <=>
            [$b['c_id'] ?? $b['r_id'], ($b['status'] ?? 'active') === 'active']
    )
);

With outdated PHP: ( Demo )

var_export(
    array_uintersect(
        $comps,
        $rests,
        function($a, $b) {
            return [$a['c_id'] ?? $a['r_id'], ($a['status'] ?? 'active') === 'active']
                   <=>
                   [$b['c_id'] ?? $b['r_id'], ($b['status'] ?? 'active') === 'active'];
        }
    )
);

I don't think that it's shameful to pre-filter the $comps array. ( Demo )

var_export(
    array_uintersect(
        array_filter($comps, function($row) { return $row['status'] === 'active'; }),
        $rests,
        function($a, $b) {
            return ($a['c_id'] ?? $a['r_id'])
                   <=>
                   ($b['c_id'] ?? $b['r_id']);
        }
    )
);

If interested in a brute force nested loop approach, then avoid doing useless cycles by conditionally breaking and continuing. I mean, think about it, why bother looping on the rests array if the given comps array can be disqualified early. Furthermore, after you make an id match and push the data into the result array, stop the inner loop. ( Demo )

$result = [];
foreach ($comps as $comp) {
    if ($comp['status'] !== 'active') {
        continue;
    }
    foreach ($rests as $rest) {
        if ($rest['r_id'] == $comp['c_id']) {
            $result[] = $rest;
            break;
        }
    }
}
var_export($result);

相关问题