How to merge collections based on object's particular key's value match in laravel6? - laravel-6

I have three collections.
SalaryCollection
BonusCollection
Deduction Collection
All of them have date which is common in some of them.
I want to merge these three into one collection in a way that object with same date in three becomes one as a result.
Something like this:
#items:array:2[
0=>{
+"date":"1-2020"
+"salaries":36500.0
+"deductions":1500.0
+"bonuses":7000.0
}
1=>{
+"date":"2-2020"
+"salaries":20000.0
+"deductions":1000.0
+"bonuses":5000.0
}
]
How can i do it?

I am not sure if this is the best way to do it but this is how i made it worked.
$salaryCollection = $salaryCollection->map(function ($item, $key) use ($bonusCollection) {
$single_bonus = $bonusCollection->where('date', $item->date);
if (!$single_bonus->isEmpty()) {
return collect($item)->put('bonuses', $single_bonus->first()->bonuses);
} else {
return collect($item)->put('bonuses', 0);
}
});
$salaryCollection = $salaryCollection->map(function ($item, $key) use ($deductionCollection) {
$single_deduction = $deductionCollection->where('date', $item['date']);
if (!$single_deduction->isEmpty()) {
return collect($item)->put('deductions', $single_deduction->first()->deductions);
} else {
return collect($item)->put('deductions', 0);
}
});

Related

Nested Loop select the minimum defined value asp.net

I have a list of states, which are defined to be ordered by min to max. the sequence is the following:
Cancelled - complete - draft - reservation - reserved - ordered - confirmed
So the cancelled is the minimum state, and confirmed is the maximum state. I may have different instances with different states, so I use a for-each loop to run through all states, and select the minimum state present in the loop.
That is: if in a list I have states [complete, reserved, draft, ordered] I need to check all the values and select complete -as it appears to be the minimum state. OR
if I have [reserved, confirmed, ordered, draft, cancelled, confirmed, confirmed] I need to select the cancelled value, as it appears to be the minimum.
I am doing the following check, but it does not seem to be working:
string globstatus = " ";
foreach (var currentstatus in list)
{
if (currentstatus == "cancelled")
{
globstatus = "cancelled";
}
else
{
if (globstatus == "cancelled")
{
return globstatus;
}
else
{
if (currentstatus == "complete")
{
globstatus = "complete";
}
else
{
if (globstatus == "complete")
{
return globstatus;
}
else
{
if (currentstatus == "draft")
{
globstatus = "draft";
}
else
{
if (globstatus == "reservation")
{
return globstatus;
}
else
{
if (currentstatus == "reserved")
{
globstatus = "reserved";
}
else
{
if (globstatus == "ordered")
{
return globstatus;
}
else
{
if (currentstatus == "confirmed")
{
globstatus = "confirmed";
}
else
{
return currentstatus;
}
}
}
}
}
}
}
}
}
}
return globstatus;
What can be the best solution to achieve the desired behavior?
I find a rule of thumb helpful that if I need more than three levels of braces, I need to rethink my code. It's hard to follow, easy to make mistakes, and a nightmare to debug. I suggest that applies here - trying to follow the flow of what all those nested if..else statements is extremely difficult.
Using Enum
My preferred solution is to achieve this using an Enum, e.g.:
var list = new List<Status>
{
Status.Complete,
Status.Draft,
Status.Draft,
Status.Confirmed
};
var minStatus = (Status)list.Select(l => (int)l).Min();
// minStatus = Status.Complete
public enum Status
{
Cancelled,
Complete,
Draft,
Reservation,
Reserved,
Ordered,
Confirmed
}
How it works: by default Enums give each value a zero-based integer, i.e. Cancelled = 0, Complete = 1 and so on. You can override this with your own values if you wish (e.g. 1/2/4/8/16 if you want to combine multiple values).
I recommend using Enum types for things like this, rather than strings. It helps avoid typos, gives someone else looking at your code a clear understanding of how your program works and its flow, and represents hierarchy in a way in which simple strings don't. (For example - does 'complete' come before or after 'draft'? Without context, I imagine most people would say after, but in this case it comes before - that is much more obvious when using an Enum.)
Parse strings to Enum
However if the statuses have to be strings, you could parse them into an enum like so:
var stringList = new List<string>
{
"complete",
"draft",
"draft",
"confirmed",
"this will be ignored"
};
var statusList = new List<int>();
foreach (var str in stringList)
{
if(Enum.TryParse(typeof(Status), str, ignoreCase: true, out object? parsed) && parsed is Status status)
{
statusList.Add((int)status);
}
}
var minStatus = (Status)statusList.Min();
// minStatus = Status.Complete
However, if it's possible to refactor your code to use the Enum in the first place, that would be a better solution, and much quicker as parsing strings has an overhead that would be good to avoid.

Laravel: Find exact match, case sensitive

This code works but it is not sensitive to case/capitalization.
public function search(){
if ($search = \Request::get('q')) {
$patrons = Patron::where(function($query) use ($search){
$query->where('barcode','=',"$search")
})->paginate(20);
}else{
$patrons = Patron::latest()->paginate(5);
}
return $patrons;
}
Example
Searching for 'banana123' should NOT be equal to 'BaNaNa123' and should return 0.
How can we make the search exact match? Thank you.
You have to use BINARY
use DB;
...
public function search(){
if ($search = \Request::get('q')) {
$patrons = Patron::where(function($query) use ($search){
$query->whereRaw("BINARY `barcode` = '$search'");
// or
// $query->where(DB::raw("BINARY `barcode`), $search);
})->paginate(20);
}else{
$patrons = Patron::latest()->paginate(5);
}
return $patrons;
}
Also if you are using one where and not chaining it to other conditions you don't need to use function inside where. you can simply write:
use DB;
...
public function search(){
if ($search = \Request::get('q')) {
$patrons = Patron::where(DB::raw("BINARY `barcode`"), $search)->paginate(20);
}else{
$patrons = Patron::latest()->paginate(5);
}
return $patrons;
}

use map function on condition in kotlin

I have a list of items and I want to edit its values before using it. I am using the map function to update each item in it. But the catch here is, I want to only update the items when the list size is 1. I want to return the list as it is if the size is larger than 1. How can I achieve this?
myList.map {
if(resources.getBoolean(R.bool.is_tablet) && it.itemList.size<6 && it.layerType == DOUBLE_LIST) {
it.layerType = SINGLE_LIST_AUTO
it.itemList.forEach {sectionItem->
sectionItem.layerType = SINGLE_LIST_AUTO
}
it
}else{
it
}
}
You can try using filter before map:
.filter { it.itemList.size == 1 }
I am assuming you want to modify the items in your list only if some conditions are met else return the same list unmodified.
You can consider using takeIf { } for this scenario if you desire to add some syntactic sugar
fun updateItemsInMyList(myList:List<SomeClass>): List<SomeClass> {
return myList
.takeIf {
// condition to modify items in your list
it.size > 1 && otherConditions
}
?.apply {
//update your items inside the list
}
?: myList // return the unmodified list if conditions are not met
}
If I understand your question correctly, you want to check if myList contains only one value else, you want update the values and return it. You could do something along the following lines,
myList.singleOrNull ?: myList.map {
if(resources.getBoolean(R.bool.is_tablet) && it.itemList.size<6 && it.layerType == DOUBLE_LIST) {
it.layerType = SINGLE_LIST_AUTO
it.itemList.forEach {sectionItem->
sectionItem.layerType = SINGLE_LIST_AUTO
}
it
}else{
it
}
}
return myList
Basically, check if there's only a single value in the list, if so, then return the value. In the case that there isn't (you get null), then you can map the value.

Yii check scenario in beforeSave()

For one action I need transform $album_id before save it to DB
in model function beforeSave() i do:
// преобразовать album -> album_id
$album_id=array();
foreach($this->string2array($this->album, '\|') as $one)
$album_id[]=Album::model()->findByAttributes(array('album' => $one))->id;
$this->album_id = $this->array2string($album_id);
but for another action I don't need this transform, because $album_id is already in proper state. So I set scenario 'batchcreate' in that action:
public function actionCreate()
{
Yii::import('ext.multimodelform.MultiModelForm');
$model = new Album('create');
$song = new Song();
$song->setScenario('batchcreate');
...
}
and try to check this scenario in model:
if(!($this->scenario === 'batchcreate')) {
// преобразовать album -> album_id
$album_id=array();
foreach($this->string2array($this->album, '\|') as $one)
$album_id[]=Album::model()->findByAttributes(array('album' => $one))->id;
$this->album_id = $this->array2string($album_id);
}
but the condition is always true. Why my scenario doesn't set or doesn't check in if statement?
Or maybe it's better to check not scenario, but make another variable, so how to set its value for 2 different cases?
my whole beforeSave():
protected function beforeSave()
{
if(parent::beforeSave())
{
// преобразовать whoes -> who
$who=array();
foreach($this->string2array($this->whoes) as $one) {
$userrow = User::model()->findByAttributes(array('username' => $one));
if($userrow) $who[]=CHtml::encode($userrow->id);
else $who[]=$one;
}
$this->who = $this->array2string($who);
//var_dump( $this->scenario );
if(!($this->scenario == 'batchcreate')) {
//if($this->notbatchcreate == 'yes') {
// преобразовать album -> album_id
$album_id=array();
foreach($this->string2array($this->album, '\|') as $one)
$album_id[]=Album::model()->findByAttributes(array('album' => $one))->id;
$this->album_id = $this->array2string($album_id);
}
return true;
}
else
return false;
}
Instead of
$song = new Song();
$song->setScenario('batchcreate');
you can simply do
$song = new Song('batchcreate');
In beforeSave()
if ( $this->scenario != 'batchcreate' ) {
echo "good - scenario is not batchcreate";
die();
}
echo 'nope...';
var_dump($this->scenario);
die();
Switch the order: call parent::beforeSave() after your code for checking the scenario. The inherited method beforeSave() may be altering your scenario.

two way mapping

Is any way, how to create two classes, which will be referenced both way and will use only one FK? This interest me in One-to-One as like as One-to-Many cases.
f.e.:
Class First: Entity
{
Second second;
}
Class Second: Entity
{
First first;
}
String TwoWayReference()
{
First Fir = new First();
Second Sec = new Second();
Fir.second = Sec; // I need it is equivalent to: Sec.first = Fir;
if (Sec.first == Fir)
return "Is any way how to do this code works and code return this string?";
else
return "Or it is impossible?"
}
simplest would be
class First : Entity
{
private Second second;
public virtual Second Second
{
get { return this.second; }
set {
if (value != null)
{
value.First = this;
this.second = value;
}
}
}
}
class Second : Entity
{
private First first;
public virtual First First
{
get { return this.first; }
set {
if (value != null && value.Second != this)
{
value.Second = this;
this.first = value;
}
}
}
}