Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ignaaaam's avatar

Compare two arrays and fill the empty values 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 dump of the 12 months and the collection:


^ array:12 [▼
  0 => "2022-02"
  1 => "2022-03"
  2 => "2022-04"
  3 => "2022-05"
  4 => "2022-06"
  5 => "2022-07"
  6 => "2022-08"
  7 => "2022-09"
  8 => "2022-10"
  9 => "2022-11"
  10 => "2022-12"
  11 => "2023-01"
]
^ Illuminate\Database\Eloquent\Collection {#1653 ▼
  #items: array:8 [▼
    "2022-01" => Illuminate\Database\Eloquent\Collection {#2078 ▶}
    "2022-02" => Illuminate\Database\Eloquent\Collection {#2079 ▶}
    "2022-03" => Illuminate\Database\Eloquent\Collection {#1655 ▶}
    "2022-04" => Illuminate\Database\Eloquent\Collection {#2049 ▶}
    "2022-06" => Illuminate\Database\Eloquent\Collection {#2019 ▶}
    "2022-08" => Illuminate\Database\Eloquent\Collection {#1651 ▶}
    "2022-09" => Illuminate\Database\Eloquent\Collection {#2027 ▶}
    "2023-01" => Illuminate\Database\Eloquent\Collection {#2021 ▶}
  ]
  #escapeWhenCastingToString: false
}

Also for each transaction if there's more than one this month, it takes the last of that month, but that is already done.

All the code I used is this but im stuck on how to compare and fill empty months 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;

                        $transactionsByMonth = $userTransactions->groupBy(function($d) {

                                $monthlyTransaction = Carbon::parse($d->created_at)->format('Y-m');

                                return $monthlyTransaction;
                        });

                        dump($dates);
                        dump($transactionsByMonth);

                        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;
                                }
                            }
                        };
0 likes
8 replies
pkboom's avatar

before I could answer, got a question.

if (sizeof($transaction) > 1) { // <-- so transaction has items.
    $duplicatedTransactions = $transaction->groupBy(function ($d) {
      return Carbon::parse($d->created_at)->format('Y-m-d');
    });
   ...
  } else { // now transaction has no items, then why loop over it?
    foreach ($transaction as $notDuplicatedTransaction) {
      $transactionDates[] = $notDuplicatedTransaction->created_at;
      $transactionBalance[] = $notDuplicatedTransaction->main_balance;
    }
  }
webrobert's avatar
Level 51

but I think there is a better way to write the code...

$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)
    ->map( fn($month) => $transactions[$month->format("Y-m")]->main_balance ?? 0 );

dd($transactionsByMonth)

EDIT: added ->map->last(); to get the last transaction of each month.

1 like
ignaaaam's avatar

@webrobert I need to work a lot using collect and Collections functions because it saves so much time, how would I replace the month key with the standar 0,1,2,3,4 array keys now if I dont need the 'Y-m' key?

Thanks a lot for your help!

ignaaaam's avatar

Thanks a lot, already solved it returning the collect with return collect($transactions[$key]->main_balance ?? 0);instead of the $key

1 like
webrobert's avatar

@ignaaaam

sorry I fell back to sleep earlier it was 2am here. California. Where are you?

I hadn't read all your code just the summary of what you wanted. so id probably do

$transactions[$key]->main_balance ?? 0

and then to reset the keys use values()

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

but if that's what you want, then lets just...

$transactionsByMonth = collect($months)
    ->map( fn($month) => $transactions[$month->format("Y-m")]->main_balance ?? 0 );
ignaaaam's avatar

Thank you, like this but instead of returning it [] I return the 0. Thanks a lot!

Please or to participate in this conversation.