0

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.

3
  • What is the expected output? Commented Sep 8, 2015 at 14:00
  • The output should be the elements from array1 with keys and values preserved but only elements with keys containing numbers from $array2 Commented Sep 8, 2015 at 14:12
  • @RyanVincent I've updated the question hopefully that clarifies it for you. Cheers. Commented Sep 8, 2015 at 14:24

2 Answers 2

2

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?

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

3 Comments

Hi Joseph, cheers for the reply. That input is a snippet of the post request where I've done nothing more than $array1 = $request->all(); The id's are appended on form creation for each row.
I've added some context to the question. This solution doesn't actually preserve the keys from $array1 which is what I need. I only wish to remove elements that do not have the attached ids specified in $array2.
I just changed $filtered[$matches[1]] = $value to $filtered[$key] = $value. Might make sense to adjust your answer to that now that I've clarified more in the original question.
0

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',
)

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.