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.
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.
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();
I have a 3 level category. I need to gain businesses on level 3 category.
I write this code:
$main_cat = Category::where(['slug' => $url])->first();
$lev_cat2 = Category::where(['parent_id' => $main_cat->id, 'status' => '1'])->get();
foreach ($lev_cat2 as $subCategory) {
$cat_ids_lv2[] = $subCategory->id . ',';
}
foreach ($lev_cat2 as $subCat) {
$lev_cat3[] = Category::where(['parent_id' => $subCat->id, 'status' => '1'])->pluck('id')->toArray();
}
dd($lev_cat3);
Then I got this array which is correct:
array:5 [▼
0 => array:3 [▼
0 => 145
1 => 146
2 => 147
]
1 => array:3 [▼
0 => 148
1 => 149
2 => 150
]
2 => array:3 [▼
0 => 151
1 => 152
2 => 153
]
3 => array:3 [▼
0 => 154
1 => 155
2 => 156
]
4 => []
]
now I dont know how can I get values like 145,146,147,148,149,... to pass theme to
Business::where(['category_id'=> [145,146,147,148,...]]->get();
of course dynamic.
You can use laravel collection helpers :
Business::whereIn('category_id', collect($lev_cat3)->flatten()->all())->get();
Since PHP 5.5.0 there is a built-in function array_column which does exactly this.
You can use it to Converting php array of arrays into single array then use it like this
$category_ids = array_column($lev_cat3);
Business::where(['category_id'=> $category_ids]]->get();
I want to remove same array between 2 array
1 ) $getAlldate
array:8 [▼
0 => "2018-08-17"
1 => "2018-08-20"
2 => "2018-08-21"
3 => "2018-08-22"
4 => "2018-08-23"
5 => "2018-08-24"
6 => "2018-08-27"
7 => "2018-08-28"
]
2) $getHoliday
array:7 [▼
0 => "2019-1-1"
1 => "2019-3-6"
2 => "2019-2-28"
3 => "2019-5-2"
4 => "2019-4-25"
5 => "2018-8-27"
6 => "2018-8-28"
]
As you see in my array 2018-08-27,2018-08-28 are duplicate with $getholiday I try to use array_diff and It still didnt work
$a = array_diff($getAllDate, $getHoliday);
$b = array_unique($a);
How can I output like this $getalldate remove same value $getHoliday
array:8 [▼
0 => "2018-08-17"
1 => "2018-08-20"
2 => "2018-08-21"
3 => "2018-08-22"
4 => "2018-08-23"
5 => "2018-08-24"
]
The format of both the dates are diffrent.
Try:
PHP Code:
$getAlldate = [
"2018-08-17",
"2018-08-20",
"2018-08-21",
"2018-08-22",
"2018-08-23",
"2018-08-24",
"2018-08-27",
"2018-08-28"
];
$getHoliday=[
"2019-1-1",
"2019-3-6",
"2019-2-28",
"2019-5-2",
"2019-4-25",
"2018-8-27",
"2018-8-28"
];
$formattedHoliday = array_map(function ($holiday) {
$alldateFormat = 'Y-m-d';
$HolidayFormat = 'Y-n-d';
$date = DateTime::createFromFormat($HolidayFormat, $holiday);
return $date->format($alldateFormat);
}, $getHoliday);
var_dump(array_diff($getAlldate, $formattedHoliday));
Output: https://3v4l.org/rCLCk
Refer:
DateTime::createFromFormat: http://php.net/manual/en/datetime.createfromformat.php
DateTime::format: http://php.net/manual/en/datetime.format.php
I have an array, and I know the desired output, but I can't quite get my head around how to achieve it
The initial indexes are the "parent" id's, and the arrays contained within are the children, but some children are also parents
My array:
```
array:10 [▼
0 => array:2 [▼
0 => 1
1 => 5
]
1 => array:1 [▼
0 => 2
]
2 => array:2 [▼
0 => 3
1 => 4
]
5 => array:1 [▼
0 => 6
]
6 => array:2 [▼
0 => 7
1 => 8
]
9 => array:2 [▼
0 => 10
1 => 22
]
10 => array:1 [▼
0 => 11
]
11 => array:10 [▼
0 => 12
1 => 13
2 => 14
3 => 15
4 => 16
5 => 17
6 => 18
7 => 19
8 => 20
9 => 21
]
22 => array:1 [▼
0 => 23
]
23 => array:2 [▼
0 => 24
1 => 25
]
]
```
The Resulting array:
```
0
9
0,1
0,5
0,1,2
0,1,2,3
0,1,2,4
0,5,6
0,5,6,7
0,5,6,8
9,10
9,22
9,10,11
9,10,11,12
9,10,11,13
9,10,11,14
9,10,11,15
9,10,11,16
9,10,11,17
9,10,11,18
9,10,11,19
9,10,11,20
9,10,11,21
9,22,23
9,22,23,24
9,22,23,25
```
I'm thinking to use recursion, but I can't for the life of me figure out how to get the result
Edit: Further information:
If I take:
22 => array:1 [▼
0 => 23
]
23 => array:2 [▼
0 => 24
1 => 25
]
23 is the parent of 24 and 25, , 22 is the parent of 23, therefore 22 is the grandparent of 24 and 25:
9,22,23,24
9,22,23,25
That's how you get the list (9 is obviously the parent of 22, therefore the grandparent of 23 and great grandparent of 24 and 25)
This is a bit advanced stuff but you can use Iterators to achieve this.
First, we have to extend RecursiveIteratorIterator to serve our need:
class FlatRecursiveIteratorIterator extends RecursiveIteratorIterator
{
private $directory;
public function __construct(
Traversable $iterator,
$mode = RecursiveIteratorIterator::LEAVES_ONLY,
$flags = 0,
array $directory
) {
// Set array for children lookup.
$this->directory = $directory;
parent::__construct($iterator, $mode, $flags);
}
public function callHasChildren()
{
if ($this->getDepth() === 0 && is_array($this->current())) {
return true;
}
// See if children array availale in the top most array
// (lookup by id).
return !empty($this->directory[$this->current()]) &&
is_array($this->directory[$this->current()]);
}
public function callGetChildren()
{
return new RecursiveArrayIterator(
$this->getDepth() === 0
? $this->current()
: $this->directory[$this->current()]
);
}
}
Having this class we use it in combination with RecursiveArrayIterator and RecursiveCallbackFilterIterator to create needed $iterator:
$skip = [];
$iterator = new FlatRecursiveIteratorIterator(
// This filter helps up skip top level array elements
// if they have ancestors. Pay attencion that $skip passed by reference.
new RecursiveCallbackFilterIterator(
new RecursiveArrayIterator($array),
function ($current, $key, $_) use (&$skip) {
return !(is_array($current) && isset($skip[$key]));
}
),
RecursiveIteratorIterator::SELF_FIRST,
0,
$array
);
Then we can traverse this $iterator with a pretty simple non-nested loop:
$stack = [];
foreach ($iterator as $node) {
$depth = $iterator->getDepth();
if ($depth > 0) {
$skip[$node] = true;
}
// Use ternary operator as top most array has ids as keys,
// but inner arrays have ids as values.
$stack[$depth] = $depth === 0
? $iterator->key()
: $node;
// We have to slice out stack, as it may contain elements
// from previous iterations.
echo implode(',', array_slice($stack, 0, $depth + 1)), PHP_EOL;
}
Here is working demo.
This might look like a lot of code, but actually, it is not. And we need to take into account that most of the work is done by Standard PHP Library. We only have written the most case specific code.
I've got a collection and I need the total users by month.
So I've done this:
array_replace(array_fill_keys(range(0, 11), 0), $users->groupBy('created_at.month')->toArray())
It's sort of working because I get this:
array:12 [▼
0 => 0
1 => 0
2 => 0
3 => 0
4 => 0
5 => 0
6 => array:1 [▶]
7 => array:2 [▶]
8 => 0
9 => 0
10 => 0
11 => 0
]
The problem I face now is that I don't need the 2 arrays at position 6 and 7 but I need the counts.
So I was thinking of something like:
$users->groupBy('created_at.month')->count()->toArray();
But, that's obviously not working. Any ideas ?
try using map method
$collection->map(function ($item, $key) {
return count($item);
});