Luke Vincent
Luke Vincent

Reputation: 1323

Find which keys of separate arrays intersect using a function

Ok so I have two arrays, one is an input array full of data like :

$array1 = ["_token" => "62d46d4h6dfh841df8h", "sku62" => "3e", "name62" => "meh", "sku61" => "3e", "name61" => "mah", "sku64" => "3e", "name64" => "moh"]

The other holds simply id's: $array2 = [64, 74, 61]

edit for clarity: $array1 is a snippet of input from a post request i.e. $array1 = $request->all(); The numbers present within the keys of this array are unique Id's appended on form generation to distinguish between rows with multiple form elements.

Each row has an "update" checkbox also with an appended unique id. When ticked this id shows up in the request e.g. update64.

$array2 was populated by doing a foreach through the request, identifying the update string and isolating the id:

foreach ($array1 as $id => $value) {

     $idInt = filter_var($id, FILTER_SANITIZE_NUMBER_INT);
     $str = preg_replace('/[0-9]+/', '', $id);

     if ($str === "update") {
         array_push($array2, $idInt);
     }
}

I want a solution that returns the elements from $array1 that have the appended ids found in $array2.

My own attempt looks like this:

$relevant_keys = function($key1, $key2) {
            return ((preg_replace('/[0-9]+/', '', $key1) === $key2)) ? 1 : -1;
        };

        $filtered = array_intersect_ukey($array1, array_flip($array2), $relevant_keys);

However $filtered is returning empty and if I dd($key2) within the function it's not even returning an element from $array2, I get something from $array1 instead so this has left me confused.

Would appreciate any help.

Upvotes: 0

Views: 53

Answers (2)

mickmackusa
mickmackusa

Reputation: 47934

I have a few important insights to share based on your coding attempt.

  1. array_intersect_ukey() should be the perfect function call for his task, but alas, it is not. I'll tell you why.

    • array_intersect_ukey() suffers in the same way as array_intersect_uassoc() and array_uintersect_uassoc() because the internal algorithm will stop looking for additional qualifying keys after it encounters its first one. I first came upon this reality here.
    • Also, the way that you've declared and used the custom function arguments ($key1 and $key2) indicates that you believe $key1 always relates to the first nominated array and $key2 always relates to the second nominated array. This is not true and I have seen many developers with this same false impression. The truth is that under the hood, the two parameters fed into the custom function may come from either array.
  2. For the reasons in #1, I'll recommend that you shift your focus to array_filter(). By establishing a lookup array containing whitelisted keys and filtering on keys, you can swiftly filter your data. Inside the callback, I am using trim() to remove the letters before the id number at the end. This is just one way of isolating the whole number at the end of each key.

Code: (Demo)

$lookup = array_flip($array2);
var_export(
    array_filter(
        $array1,
        fn($key) => isset($lookup[ltrim($key, 'a..z')]),
        ARRAY_FILTER_USE_KEY
    )
);

Output:

array (
  'sku61' => '3e',
  'name61' => 'mah',
  'sku64' => '3e',
  'name64' => 'moh',
)

Upvotes: 0

Joseph Silber
Joseph Silber

Reputation: 219946

Here's the solution to the exact problem you posted:

$filtered = [];

foreach ($array1 as $key => $value)
{
    if ( ! preg_match('/(\d+)$/', $key, $matches)) continue;

    if ( ! isset($matches[1]) || ! in_array($matches[1], $array2)) continue;

     $filtered[$key] = $value;
}

But I'm not sure you're approaching this correctly. That input looks suspicious.

Are you sure there's no better way to format the request?

Upvotes: 2

Related Questions