A. Appleby
A. Appleby

Reputation: 469

Compare an associative array where array2 has additional keys

Is there a fast way to compare two arrays, where the second array contains all the keys from the first, but also has additional keys?

For example, given the two arrays below, I would want the final two elements from the first array as they do not exist on the second:

$input = [
    [
        'firstName' => 'Paula',
        'lastName' => 'Fisher',
        'companyName' => 'Ankunding-Braun'
    ],
    [
        'firstName' => 'Elliot',
        'lastName' => 'Roob',
        'companyName' => 'Feeney PLC'
    ],
    [
        'firstName' => 'Jammie',
        'lastName' => 'Morar',
        'companyName' => 'Pollich PLC'
    ],
    [
        'firstName' => 'Tyrell',
        'lastName' => 'Mills',
        'companyName' => 'Oberbrunner, Kulas and Rice'
    ],
    [
        'firstName' => 'Fred',
        'lastName' => 'Johnson',
        'companyName' => 'Pollich PLC'
    ],
    [
        'firstName' => 'Tyrell',
        'lastName' => 'Bloggs',
        'companyName' => 'BBC East'
    ],
];

$output = [
    [
        "id" => 1,
        "firstName" => "Paula",
        "lastName" => "Fisher",
        "salutation" => "Prof.",
        "email" => "[email protected]",
        "phone" => "1-887-271-5742 x394",
        "mobileNumber" => "1-558-612-4089 x45355"
    ],
    [
        "id" => 2,
        "firstName" => "Elliot",
        "lastName" => "Roob",
        "salutation" => "Prof.",
        "email" => "[email protected]",
        "phone" => "+1-378-385-3633",
        "mobileNumber" => "1-815-769-2297",
    ],
    [
        "id" => 3,
        "firstName" => "Jammie",
        "lastName" => "Morar",
        "salutation" => "Mr.",
        "email"=> "[email protected]",
        "phone" => "(694) 767-1593 x5966",
        "mobileNumber" => "204-991-3292",
    ],
    [
        "id" => 4,
        "firstName" => "Tyrell",
        "lastName" => "Mills",
        "salutation"=> "Mrs.",
        "email" => "[email protected]",
        "phone" => "462-385-0569 x22876",
        "mobileNumber" => "532-369-9039"
    ]
];

As a little bit of context, I am trying to return all records that do not exist on the database (checking first name, last name and company name). If there's a faster way of doing this using the database that would be great, but I can't think of anything myself, so I've returned the records that are found, and now want to remove the found records from the searched array - therefore leaving me with the records that do not exist.

Upvotes: 0

Views: 38

Answers (1)

Jared Farrish
Jared Farrish

Reputation: 49188

To find the searches not found in the results, you can:

// I can't "query", this is for demonstration based on the question data.
// The assumption here is that this is a hydrated to array resultset from a
// Doctrine ORM query, but it should work for any array comparison of this 
// sort.
$filtered = array_filter($output, function($row) use($input) {
    return array_reduce($input, function($carry, $compare) use($row) {
        return $carry || (
            $compare['firstName'] == $row['firstName']
            && $compare['lastName'] == $row['lastName']
            // Uncomment this if you want, and have, companyName to compare.
            // && $compare['companyName'] == $row['companyName']
        );
    });
});

$notfound = array_filter($input, function($search) use($filtered) {
    // Note the negation here, this uses array_reduce() to tell us when
    // there's a "hit", we're looking for $search rows with no "hit".
    return !array_reduce($filtered, function($carry, $row) use($search) {
        return $carry || (
            $search['firstName'] == $row['firstName']
            && $search['lastName'] == $row['lastName']
            // Uncomment this if you want, and have, companyName to compare.
            // Note that the hydrated resultset needs to account for this.
            // && $compare['companyName'] == $row['companyName']
        );
    });
});

https://3v4l.org/Rck9V

Upvotes: 1

Related Questions