Jakub Zych
Jakub Zych

Reputation: 39

Search array of objects for multidimensional array values in PHP

I have following task to do, if there is any chance I would appreciate some help to make it in as efficient way as possible. I need to compare values from array of objects (which comes from Laravel Query Builder join query) with array values.

Objects consist of database stored values:

0 => array:2 [
  0 => {#912
    +"addition_id": 1
    +"valid_from": "2015-09-13 00:00:00"
    +"valid_to": "2015-09-19 00:00:00"
    +"price": "0.00"
    +"mode": 0
    +"alias": "Breakfast"
  }
  1 => {#911
    +"addition_id": 2
    +"valid_from": "2015-09-13 00:00:00"
    +"valid_to": "2015-09-19 00:00:00"
    +"price": "10.00"
    +"mode": 1
    +"alias": "Dinner"
  }

while array includes new data, being processed by my method.

0 => array:3 [
  0 => array:6 [
    "id" => 1
    "alias" => "Breakfast"
    "price" => "0.00"
    "mode" => 0
    "created_at" => "2015-09-12 21:25:03"
    "updated_at" => "2015-09-12 21:25:03"
  ]
  1 => array:6 [
    "id" => 2
    "alias" => "Dinner"
    "price" => "10.00"
    "mode" => 1
    "created_at" => "2015-09-12 21:25:18"
    "updated_at" => "2015-09-12 21:25:18"
  ]
  2 => array:6 [
    "id" => 3
    "alias" => "Sauna Access"
    "price" => "50.00"
    "mode" => 0
    "created_at" => "2015-09-12 21:25:35"
    "updated_at" => "2015-09-12 21:25:35"
  ]
 ]

Now, what I need to do is to find out what position of the array was not in the object (compare id with addition_id) and return it.

Is there any way to do it without two nested foreach loops? I think it can be done somehow smart with array_filter, but I'm not really sure how to write efficient callback (beginner here).

The only way I could get around this was:

private function compareAdditions(array $old,array $new)
{
    $difference = $new;

    foreach($new as $key => $value) {
        foreach($old as $oldEntry) {
            if($oldEntry->addition_id == $value['id']) {
                unset($difference[$key]);
            }
        }
    }

    return $difference;
}

But I would really like to make it without two foreach loops. Help will be very appreciated :)

Upvotes: 1

Views: 539

Answers (1)

DarkMukke
DarkMukke

Reputation: 2489

This might be overkill but it uses a function i write in every project, precisely for these kind of situations :

function additionals($original, $additions) {
    $nonExisiting = [];
    //convert all the objects in arrays
    $additions = json_decode(json_encode($additions), true);
    //create an index
    $index = hashtable2list($original, 'id');
    for(reset($additions); current($additions); next($additions)) {
        $pos = array_search(current($additions)['addition_id'], $index);
        if($pos !== false) {
            //We could replace the originals with the additions in the same loop and save resources
            //$original[$pos] = current($additions);
        } else {
            $nonExisiting[] = current($additions);
        }
    }
    return $nonExisiting;
}

function hashtable2list( $hashtable, $key ){
    $array = [];
    foreach($hashtable as $entry) {
        if( is_array($entry) && isset($entry[$key])) {
            $array[] = $entry[$key];
        } elseif( is_object($entry) && isset($entry->$key)  ) {
            $array[] = $entry->$key;
        } else {
            $array[] = null;
        }
    }
    return $array;
}

Upvotes: 1

Related Questions