Search code examples
phparrayslaravelcollections

Compare two arrays and if one month (key) is missing fill with 0


Hello I've got two arrays, one which is made with Carbon that takes the last 12 months from today (in Y-m format) and a Collection (which have an array of items that return every transaction of the last 12 months in the same Y-m format). What I want to do is fill in this items array if there's no transaction for example on the month 12, 9, 8 fill them with 0.

Here's the 2 arrays I need compared and fill missing Year-month with 0 (the last array is the balance which will be merged into the array for every month).

^ array:12 [▼
  "2022-02" => 0
  "2022-03" => 0
  "2022-04" => 0
  "2022-05" => 0
  "2022-06" => 0
  "2022-07" => 0
  "2022-08" => 0
  "2022-09" => 0
  "2022-10" => 0
  "2022-11" => 0
  "2022-12" => 0
  "2023-01" => 0
]
^ array:12 [▼
  "2022-01" => 0
  "2022-02" => 1
  "2022-03" => 2
  "2022-04" => 3
  "2022-06" => 4
  "2022-07" => 5
  "2022-08" => 6
  "2022-09" => 7
  "2022-10" => 8
  "2022-11" => 9
  "2022-12" => 10
  "2023-01" => 11
]
^ array:12 [▼
  0 => 340
  1 => 480
  2 => 550
  3 => 690
  4 => 830
  5 => 970
  6 => 1110
  7 => 1250
  8 => 1460
  9 => 1600
  10 => 1670
  11 => 1880
]

The code I used at the moment to find the balance per month (the latest balance of the month) but at the moment I dont print the missing months (it just skips them instead of filling with 0):

$period = CarbonPeriod::create(now()->subMonths(11), now())->month();

                        $dates = array();
                        $days = array();
                        
                        foreach($period as $date) {
                            $dates[] = $date->format("Y-m");
                            $days[] = $date->lastOfMonth()->format("d-m-Y");
                        }

                        $userTransactions = auth()->user()->transactions;

                        $flipped = array_flip($dates);

                        $transactionsByMonth = $userTransactions->groupBy(function($d) {
                                $monthlyTransaction = Carbon::parse($d->created_at)->format('Y-m');

                                return $monthlyTransaction;
                        });

                        foreach($flipped as $key => $yearMonth){
                            $yearMonth = 0;
                            $flipped[$key] = $yearMonth;
                        }

                        dump($flipped);

                        foreach($transactionsByMonth as $transaction) {
                            if (sizeof($transaction) > 1){
                                $duplicatedTransactions = $transaction->groupBy(function($d) {
                                    return Carbon::parse($d->created_at)->format('Y-m-d');
                                });

                                $lastDuplicatedTransactions = $duplicatedTransactions->last();
                                foreach($lastDuplicatedTransactions as $lastTransaction){
                                    $transactionDates[] = $lastTransaction->created_at;
                                    $transactionBalance[] = $lastTransaction->main_balance;
                                }
                            } else {
                                foreach($transaction as $notDuplicatedTransaction){
                                    $transactionDates[] = $notDuplicatedTransaction->created_at;
                                    $transactionBalance[] = $notDuplicatedTransaction->main_balance;
                                }
                            }
                        };

                        $transactionsPerMonth = [];

                        foreach($transactionDates as $date){
                            $date = Carbon::parse($date)->format('Y-m');
                            $transactionsPerMonth[] = $date;
                        }

                        $transactionsPerMonth = array_flip($transactionsPerMonth);
                        dump($transactionsPerMonth);
                        dump($transactionBalance);

At the moment I achieved printing the balance of the oldest day of the month on the last 12 months, what Im missing is comparing if of this 12 months if there's a month missing fill it with 0 instead of skipping it.


Solution

  • Improved the code to this:

    $months = CarbonPeriod::create(now()->subMonths(11), now())->month();
            
                                    $transactions = auth()->user()->transactions
                                                    ->groupBy( fn($d) => Carbon::parse( $d->created_at )->format('Y-m'))->map->last();
                                    
                                    $transactionsByMonth = collect($months)
                                            ->flatMap(function ($key) use ($transactions) {
                                                $key = $key->format('Y-m');
                                                return [$key => collect($transactions[$key]->main_balance ?? 0)];
                                            });
                                    $transactionsByMonth = $transactionsByMonth->toArray();
                                    $transactionsByMonth = array_values($transactionsByMonth);
                                    dump($transactionsByMonth);
        
       
    
     But Im getting an array inside an array:
        
           array:12 [▼
              0 => array:1 [▼
                0 => 480
              ]
              1 => array:1 [▼
                0 => 550
              ]
              2 => array:1 [▼
                0 => 690
              ]
              3 => array:1 [▶]
              4 => array:1 [▶]
              5 => array:1 [▶]
              6 => array:1 [▶]
              7 => array:1 [▶]
              8 => array:1 [▶]
              9 => array:1 [▶]
              10 => array:1 [▶]
              11 => array:1 [▶]
            ]
    

    So What I finally did to solve it was instead of returning the collect() for every $key I just returned the collect directly so I would stop getting an array inside an array.

    Replaced this:

        $transactionsByMonth = collect($months)
                                        ->flatMap(function ($key) use ($transactions) {
                                            $key = $key->format('Y-m');
                                            return [$key => collect($transactions[$key]->main_balance ?? 0)];
                                        });
                                $transactionsByMonth = $transactionsByMonth->toArray();
                                $transactionsByMonth = array_values($transactionsByMonth);
                                dump($transactionsByMonth);
    

    Into this:

        $transactionsByMonth = collect($months)
                                        ->flatMap(function ($key) use ($transactions) {
                                            $key = $key->format('Y-m');
                                            return collect($transactions[$key]->main_balance ?? 0);
                                        });
                                $transactionsByMonth = $transactionsByMonth->toArray();