skip to Main Content

I have an array that contains data of incoming mail, looks something like this:

$incomingMail = [
   0 => [
      'title' => 'Title 1',
      'areaCode' => 101
   ],
   1 => [
      'title' => 'Title 2',
      'areaCode' => 101
   ],
   2 => [
      'title' => 'Title 3',
      'areaCode' => 102
   ]
];

And another array containing area name and code, the array looks like this:

$areaArr = [
   0 => [
      'name' => 'Area 1',
      'code' => 101
   ],
   1 => [
      'name' => 'Area 2',
      'code' => 102
   ],
   2 => [
      'name' => 'Area 3',
      'code' => 103
   ],
   3 => [
      'name' => 'Area 4',
      'code' => 104
   ]
];

I want to create an array that contains the count of incomingMail array based on areaArr‘s code, it will kind of looks like this:

$areaWithMailCount = [
   0 => [
      'areaName' => 'Area 1',
      'areaCode' => 101,
      'mailCount' => 2
   ],
   1 => [
      'areaName' => 'Area 2',
      'areaCode' => 102,
      'mailCount' => 1
   ],
   2 => [
      'areaName' => 'Area 3',
      'areaCode' => 103,
      'mailCount' => 0
   ],
   3 => [
      'areaName' => 'Area 4',
      'areaCode' => 104,
      'mailCount' => 0
   ]
];

I have tried to loop those arrays and add the condition based on area code but the result isn’t quite what I wanted, the code looks something like this:

$areaWithMailCount = [];

foreach($areaArr as $area) {
   foreach($incomingMail as $mail) {
      if($mail['areaCode'] == $area['code']) {
         $areaWithMailCount[] = [
            'areaName' => $area['name'],
            'areaCode' => $area['code'],
            'mailCount' => count($mail)
         ];
      }
   }
}

The result from above code is like this:

[
  0 => [
    "areaName" => "Area 1"
    "areaCode" => 101
    "mailCount" => 2
  ],
  1 => [
    "areaName" => "Area 1"
    "areaCode" => 101
    "mailCount" => 2
  ],
  2 => [
    "areaName" => "Area 2"
    "areaCode" => 102
    "mailCount" => 2
  ]
];

Any ideas how to achieve that?

2

Answers


  1. It is inefficient to use nested loops — this will make your server do loads of unnecessary cycles while searching for qualifying values.

    Instead, loop the $incomingMail array only once and populate a lookup array which the $areaArr array can reference as it is iterated. If the code in the $areaArr does not related to any keys in the lookup array, then default the value to 0.

    Code: (Demo)

    $lookup = [];
    foreach ($incomingMail as $row) {
        $lookup[$row['areaCode']] = ($lookup[$row['areaCode']] ?? 0) + 1;
    }
    
    $result = [];
    foreach ($areaArr as $row) {
        $result[] = [
            'areaName' => $row['name'],
            'areaCode' => $row['code'],
            'mailCount' => $lookup[$row['code']] ?? 0
        ];
    }
    
    var_export($result);
    

    The functional-style equivalent of the above 2-loop snippet looks like this: Demo

    $lookup = array_reduce(
        $incomingMail,
        function($result, $row) {
            $result[$row['areaCode']] = ($result[$row['areaCode']] ?? 0) + 1;
            return $result;
        }
    );
    
    var_export(
        array_map(
            fn($row) =>
                [
                    'areaName' => $row['name'],
                    'areaCode' => $row['code'],
                    'mailCount' => $lookup[$row['code']] ?? 0
                ],
            $areaArr
        )
    );
    

    Or even: Demo

    var_export(
        array_map(
            function($row) use ($incomingMail) {
                static $lookup;
                $lookup ??= array_reduce(
                    $incomingMail,
                    function($result, $row) {
                        $result[$row['areaCode']] = ($result[$row['areaCode']] ?? 0) + 1;
                        return $result;
                    }
                );
                return [
                    'areaName' => $row['name'],
                    'areaCode' => $row['code'],
                    'mailCount' => $lookup[$row['code']] ?? 0
                ];
            },
            $areaArr
        )
    );
    
    Login or Signup to reply.
  2. I know this has been answered but just to add a bit of a cleaner way.

    This is essentially using the same process as https://stackoverflow.com/a/75443993/1791606 but is too big for a comment so I’ve stuck it in an answer.

    $mailCounts = array_count_values(array_column($incomingMail, 'areaCode'));
    
    $areaWithMailCount = array_map(fn(array $area) => [
        'areaName'  => $area['name'],
        'areaCode'  => $area['code'],
        'mailCount' => $mailCounts[$area['code']] ?? 0,
    ], $areaArr);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search