Home > Back-end >  Compare two arrays and if one month (key) is missing fill with 0
Compare two arrays and if one month (key) is missing fill with 0

Time:01-23

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.

CodePudding user response:

You can use array_key_exists() function to compare the two arrays and fill in missing months with 0. Example:

$carbonMonths = ["2022-01", "2022-02", "2022-03", "2022-04", "2022-05", "2022-06", "2022-07", "2022-08", "2022-09", "2022-10", "2022-11", "2022-12"];
$transactions = [
    ["2022-01" => 200],
    ["2022-02" => 150],
    ["2022-03" => 100],
    ["2022-05" => 50]
];

foreach ($carbonMonths as $month) {
    if (!array_key_exists($month, $transactions)) {
        $transactions[$month] = 0;
    }
}

In this example, the $carbonMonths array contains the last 12 months in Y-m format. The $transactions array contains transactions in the same format.

You can also use the array_merge() function to merge the two arrays and fill in any missing values with 0.

$merged = array_merge(array_fill_keys($carbonMonths, 0), $transactions);

Here $transactions should be an associative array with keys as month and value for this to work.

Both of the approach should give you the same result, you may use the one which you find easy to implement.

CodePudding user response:

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 I'm 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 [▶]
]
  • Related