MasterSmack
MasterSmack

Reputation: 383

PHP efficient way to combine two associative arrays into one multidimensional associative array

This is the first problem:

I have two Associative Arrays, one containing sales persons and one containing clients.

  $salesPersons = array(
    array(
      "id" => "1",
      "name" => "Mr Smith",
      "email" => "[email protected]",
      "clients" => array()
    ),
    array(
      "id" => "2",
      "name" => "James Bond",
      "email" => "[email protected]",
      "clients" => array()
    )
  );

  $clients = array(
    array(
      "id" => "1",
      "name" => "Lucifer Enterprises",
      "salesPersonId" => "1"
    ),
    array(
      "id" => "2",
      "name" => "Charlies Chocolate Factory",
      "salesPersonId" => "1"
    ),
    array(
      "id" => "3",
      "name" => "Geckos Investments",
      "salesPersonId" => "2"
    ),
  );


I want to map $salesPersons['id'] to clients['salesPersonId'] by ID and return a multidimensional associative array like this:

  $result_i_want = array(
    array(
      "id" => "1",
      "name" => "Mr Smith",
      "email" => "[email protected]",
      "clients" => array(
        array(
          "id" => "1",
          "name" => "Lucifer Enterprises",
        ),
        array(
          "id" => "2",
          "name" => "Charlies Chocolate Factory",
        ),
      )
    ),
    array(
      "id" => "2",
      "name" => "James Bond",
      "email" => "[email protected]",
      "clients" => array(
        array(
          "id" => "3",
          "name" => "Geckos Investments",
        ),
      )
    )
  );

My solution to the first problem

I have solved it using nested foreach-loops and array_push

  $result = array();

  foreach ($clients as $c_record) {
    foreach ($salesPersons as $s_record) {
      if ($c_record['salesPersonId'] == $s_record['id']) {
        array_push($s_record['clients'], array(
          "id" => $c_record['id'],
          "name" => $c_record['name']
        ));
        array_push($result, $s_record);
      }
    }
  }

The remaining problem

This solution doesn't seem to be very efficient. For each client record I check all sales persons to see if there is a match. I think the number of computations are:

no. of clients * no. of sales persons

I have a huge database and also need to add even more dimensions by mapping projects to the clients and deliverables to the projects. I think this could pose a problem.

Question

Is there a more efficient way to get the same result?

Upvotes: 2

Views: 97

Answers (2)

Lenny4
Lenny4

Reputation: 1678

As LeGEC said:

you need to access your salesPerson entries by id, you can start by creating an associative array id => salesPerson, and then use this associative array in your loop.

You need to set the index of your arrays with the id:

<?php
$salesPersons = array(
    1 => array(
        "id" => "1",
        "name" => "Mr Smith",
        "email" => "[email protected]",
        "clients" => array()
    ),
    2 => array(
        "id" => "2",
        "name" => "James Bond",
        "email" => "[email protected]",
        "clients" => array()
    )
);

$clients = array(
    1 => array(
        "id" => "1",
        "name" => "Lucifer Enterprises",
        "salesPersonId" => "1"
    ),
    2 => array(
        "id" => "2",
        "name" => "Charlies Chocolate Factory",
        "salesPersonId" => "1"
    ),
    3 => array(
        "id" => "3",
        "name" => "Geckos Investments",
        "salesPersonId" => "2"
    ),
);

Then:

$result = array();
foreach ($clients as $id => $c_record) {
    if (isset($salesPersons[$id])) {
        $result[] = array_merge($clients[$id], $salesPersons[$id]);
    } else {
        $result[] = $clients[$id];
    }
}
var_dump($result);

Result here: http://sandbox.onlinephpfunctions.com/code/e590bdb5aaea2794fc5a04ee60f61db766129664

PS:

My code works with your use case, but it will not work if the size of the $salesPersons array is bigger than the $clients array

Upvotes: 0

LeGEC
LeGEC

Reputation: 51860

Build an index :
you need to access your salesPerson entries by id, you can start by creating an associative array id => salesPerson, and then use this associative array in your loop.

$salesById = array();

foreach ($salesPersons as $s_record) {
    $salesById[ $s_record['id'] ] = $s_record;
}

$result = array();

foreach ($clients as $c_record) {
    $s_record = $salesById[ $c_record['salesPersonId'] ];

    if ($s_record == null) {
        // you may want to handle invalid ids in the client array
        // one way is to simply ignore this client record :
        continue;
    }

    array_push($s_record['clients'], array(
      "id" => $c_record['id'],
      "name" => $c_record['name']
    ));
    array_push($result, $s_record);
}

Notes

There may be a problem in the way you create your $result array :
if a sales person has n clients, the $result array will reference that sales person n times.

Look closer into what result you actually want, you may simply want to return $salesPersons, or $salesById.

Upvotes: 2

Related Questions