user1801810
user1801810

Reputation: 614

Comparing Two Arrays for Two Values

I'm struggling with the appropriate logic to compare the following arrays:

$a = [
    "ip" => [
        "1.2.3.4",
        "4.3.2.1",
    ],
    "domain" => [
        "example.com",
        "another.domain",
    ],

];

$b = [
    [
        "id"=> 136589,
        "metaname" => "ip",
        "metavalue" => "1.2.3.4",
    ],
    [
        "id"=> 136590,
        "metaname" => "domain",
        "metavalue" => "example.com",
    ],
];

I need to loop over $a to find the key ('ip') value ('1.2.3.4') combinations that do not exist in $b. In the array $a, I need to capture the ip '4.3.2.1' and the domain 'another.domain'

It is possible for $b to have matching values with different keys?

A good example is that of 'ip' addresses. Possible IP-related metaname values are 'ip', 'ip.dst' and 'ip.src'. Back to the sample data - even if the 'ip' matches, if the metaname does not match it should be skipped.

foreach ($a as $metaName => $metaValues)
{
    foreach ($metaValues as $metaValue)
    {
        foreach ($b as $row)
        {
            if (in_array($metaName, $row) && in_array($metaValue, $row))
            {
                # this pair exists, move on to next $metaName-$metaValue pair
                break;
            }
            # this is where i am now, making small progress
            # more trial and error going on
        }
    }
}

In my sample code the comment is where I need help. I've tried various iterations of different checks and loops to capture the appropriate data to no avail...

combined with various if statements and so on but that won't help.

In the event that my description failed to be clear maybe the following table will help.

+ A ---------------------+----+ B ------------------+ Comment ------------------------+
| ip, 1.2.3.4            | == | ip, 1.2.3.4         | Skip, no more checks            |
+------------------------+----+---------------------+---------------------------------+
| ip, 4.3.2.1            | != | ip, 1.2.3.4         | Keep checking                   |
|                        | != | domain, example.com | No more B to compare, I want A! |
+------------------------+----+---------------------+---------------------------------+
| domain, example.com    | != | ip, 1.2.3.4         | Keep checking                   |
|                        | == | domain, example.com | Skip, no more checks            |
+------------------------+----+---------------------+---------------------------------+
| domain, another.domain | != | ip, 1.2.3.4         | Keep checking                   |
|                        | != | domain, example.com | No more B to compare, I want A! | 
+------------------------+----+---------------------+---------------------------------+

Upvotes: 5

Views: 112

Answers (1)

With just a slight modification and the use of a reference you are pretty close. But be careful with the first foreach, the first argument is a $metaname, but the second is not yet the $metavalue, you need a second foreach to loop over them:

foreach ($a as $metaname => &$group) { // & is present to unset the original array
    foreach ($group as $i => $metavalue) { // here you get the distinct metavalues
        foreach ($b as $row) {
            if (!($row['metaname'] === $metaname)) {
                continue;
            }
            if ($row['metavalue'] === $metavalue) {
                unset($group[$i]);
            }
        }
    }
}

var_dump($a);

a var_dump() of $a afterwards

array(2) {
  ["ip"]=>
  array(1) {
    [1]=>
    string(7) "4.3.2.1"
  }
  ["domain"]=>
  &array(1) {
    [1]=>
    string(14) "another.domain"
  }
}

The first foreach() would access the distinct values of $a arrays whereas $metavalue is in fact the array containing those metavalues.

Upvotes: 2

Related Questions