Loop through collection in laravel and get specific data from the collection - laravel

I'm trying to go through a collection and I need to get a list of products according to certain keys. but I get the following error when I print the list with dd:
"array_key_exists(): The first argument should be either a string or an integer"
this is my function
public function reemplazaCostoZona($zona, $destino, $especie, $costo, $transporCollect){
$productos = $transporCollect->where([['zona',$zona],['destino', $destino],['especie',$especie]])
->pluck('producto');
dd($productos );
}
Collection:
I need to obtain the list of products for destination zone and species, That is to say that for my example of collection, for zone 1 destination 5 specie 1 I would have in my list product 1 and there may be more.
function where Im obtain collection:
public function storeTranspor3($request){
DB::table('transpor')->truncate();
$var = DB::select("select flu.zona, flu.destino, flu.producto, pro.especie, sup.codigo, dtr.cod_fundo, sup.sup_ha, dtr.dist_pavimento, dtr.dist_no_pavimento, dtr.peaje
from flujos flu
left join super sup on (sup.zona = flu.zona)
left join d_transporte dtr on (dtr.cod_fundo = (sup.codigo / 1000000) and dtr.destino = flu.destino)
left join productos pro on (pro.producto = flu.producto)
left join especies esp on (esp.especie = pro.especie)
order by flu.zona, dtr.cod_fundo, flu.producto, flu.destino, sup.codigo");
$tansporCollect = collect();
$tansporCollectsinCosto = collect();
foreach ($var as $f) {
if($f->codigo != null){
if($f->especie == 1){
$a = 0.177548*$f->dist_no_pavimento;
$b = 0.0746*$f->dist_pavimento;
$c = 0.0333*$f->peaje;
$costoFundo = ($a + $b + 1.1191 + 0.399 + $c)*$f->sup_ha;
}
else{
$a = 0.1652*$f->dist_no_pavimento;
$b = 0.0694*$f->dist_pavimento;
$c = 0.0357*$f->peaje;
$costoFundo = ($a + $b + 1.0421 + 0.599 + $c)*$f->sup_ha;
}
$tansporC =[
'zona' => $f->zona,
'destino' => $f->destino,
'producto' => $f->producto,
'especie' => $f->especie,
'costo' => $costoFundo
];
$tansporCollect->push($tansporC);
$tansporsinCosto = [
'zona' => $f->zona,
'destino' => $f->destino,
'producto' => $f->producto,
'especie' => $f->especie,
];
$tansporCollectsinCosto->push($tansporsinCosto);
}
}
$zonas = $tansporCollect->pluck('zona')->unique();
$destinos = $tansporCollect->pluck('destino')->unique();
$especies = $tansporCollect->pluck('especie')->unique();
$transporCollectUnique = $tansporCollectsinCosto->unique();
foreach($zonas as $zon){
$costoZona = $tansporCollect->where('zona',$zon);
foreach($destinos as $destin){
$costoDestino = $costoZona->where('destino',$destin);
foreach($especies as $espec){
$costoEspecie = $costoDestino->where('especie',$espec)->avg('costo');
/*HERE IM CALL OTHER FUNCTION */
$this->reemplazaCostoZona($zon, $destin, $espec, $costoEspecie, $transporCollectUnique);
}
}
}
}
I'm with laravel 5.8

You are not using the where function of collections correctly. For collections you need the following:
$productos = $transporCollect->where('zona', $zona)
->where('destino', $destino)
->where('especie',$especie)
->pluck('producto');
Hope that helps!

Related

Get Group sum not using group.Sum() in linq

The following query works, but I want to get the same result without using grp.Sum(). Can we do it?
from item in (await VehicleReplaceCostDataAsync())
group item by (item.type, item.size, item.ADA, item.eseq) into grp
orderby (grp.Key.eseq, grp.Key.size, grp.Key.ADA)
select new VehicleReplacementCost
{
type = grp.Key.type,
size = grp.Key.size,
ADA = grp.Key.ADA,
count = grp.Sum(x => x.count),
cost = grp.Sum(x => x.cost),
Fcount = grp.Sum(x => x.Fcount),
Fcost = grp.Sum(x => x.Fcost),
eseq = grp.Key.eseq,
}).ToList();
Perhaps by using .Aggregate()? [docs]
count = grp.Aggregate(0, (a, b) => a + b.count)
Thanks for the answer from Astrid. It looks like a good one, but I didn't test it. My colleague gave this solution instead by using yield:
var groups = costs
.GroupBy(type => (type.SystemId, type.Type, type.Size, type.ADA, type.Eseq))
.OrderBy(group => (group.Key.SystemId, group.Key.Eseq, group.Key.Size, group.Key.ADA));
foreach (var group in groups)
{
var result = new ProgramGuideVehicleCostRow
{
SystemId = group.Key.SystemId,
Type = group.Key.Type,
Size = group.Key.Size,
ADA = group.Key.ADA,
};
foreach (var row in group)
{
result.Cost += row.Cost;
result.Fcost += row.Fcost;
result.Count += row.Count;
result.Fcount += row.Fcount;
}
yield return result;
}

laravel get items from two separate table and merge the result with pagination

I have two tables, one of them is "posts" and the other one is "notifications". I want to show the users a list of posts and notifications with pagination. how can I do that efficiently?
I have this code that works fine but it is not efficient because I get all the data and then slice them. I want to do the pagination, using MYSQL
public function list_post_notification(Request $request , $page_number = 1 , $per_page=10 , $brand_id = null ){
$brand =$this->brandRepository->getMagazinBrand() ;
$posts = $brand->posts()->orderBy('posts.created_at' , 'desc')->take($page_number * $per_page) ;
$notifs = $brand->notifications()->orderBy('notifications.created_at' , 'desc')->take($page_number * $per_page) ;
$result = [] ;
foreach ($posts->get() as $k=>$v){
$item = [
'type'=>'post' ,
'uuid'=>$v->uuid,
'title'=>$v->title,
'created_at'=>strtotime($v->created_at),
'creator'=>$v->brand->fa_name,
'brand_id'=>$v->brand->id,
];
$result[$item['created_at']] =$item ;
}
foreach ($notifs->get() as $k=>$v){
$item = [
'type'=>'notification' ,
'uuid'=>$v->uuid,
'title'=>$v->title,
'created_at'=>strtotime($v->created_at),
'creator'=>$v->brand->fa_name,
'brand_id'=>$v->brand->id,
];
$result[$item['created_at']] =$item ;
}
krsort($result) ;
$start = 0 ;
if ($page_number > 1)
$start = ($page_number -1 ) * $per_page ;
return response()
->json(array_slice($result , $start , $per_page)) ;
}
You can merge all your items and create one Collection.
$resultCollection = collect($result).
Than use forPage method.

Algorithm: optimally distribute N people among M tasks given P preferences

Example: 10 candidates each give 2 preferences (the first being more preferred than the second) for 3 available jobs, and their boss must then optimally allocate (and evenly distribute) them evenly based on their preferences. Obviously, unwanted jobs will require some random draw.
How would I write an algorithm that calculates this optimal allocation automatically?
I looked around and found bipartite graphs which might give me some clues, however I am having trouble wrapping my head around it!
For the "luck" aspect of the game, I already implemented a simple Fisher Yates Shuffle.
Preference weight:
If there are 2 preferences, when assigned to a worker, obtaining a first choice weighs +2, a second choice +1, an unwanted choice -1 (for example). The "optimality" goal is to maximize the aggregate preferences.
Your question is quite challenging, but i found a working (maybe not the most performant) solution. My Example is written in PHP, but you should be able to adapt it. I'll try to explain the "thoughts" behind the code.
Note: It seems like you added the "10 persons, 3 Jobs" constraint later - or i simple did overread it. However, my code should give you an example that you might be able to adapt to that constraint. My Code currently is assuming that there are n jobs for n persons. (The most easiest way of adapting it to the 10/3 criteria, would be to split up the 3 Jobs into 10 equal units of work, when assuming 10 workers!)
First, lets create some basic architecture stuff. We need person, job and obviously a matrix, representing the satisfaction of a person towards a job. The following snipped does exactly that:
<?php
class Person{
var $name;
var $prim;
var $sec;
function __construct($name, $prim, $sec){
$this->name = $name;
$this->prim = $prim;
$this->sec = $sec;
}
function likes($job){
if ($job->type == $this->prim) return 2;
if ($job->type == $this->sec) return 1;
else return -1;
}
}
class Job{
var $name;
var $type;
function __construct($name, $type){
$this->name = $name;
$this->type = $type;
}
}
$persons = array(
"Max" => new Person("Max", "programing", "testing"),
"Peter" => new Person("Peter", "testing", "docu"),
"Sam" => new Person("Sam", "designing", "testing")
);
$jobs = array(
"New Classes" => new Job("New Classes", "programing"),
"Theme change" => new Job("Theme change", "designing"),
"Test Controller" => new Job("Test Controller", "testing")
);
// debug: draw it:
echo "<h2>Happines with Jobs</h2> ";
echo "<table border=1>";
$p=0;
echo "<tr>";
foreach ($jobs AS $job){
$j=0;
foreach ($persons as $person){
if ($p++==0){
echo "<tr><td></td>";
foreach ($persons as $per) {
echo "<td>".$per->name."</td>";
}
echo "</tr>";
}
if ($j++==0){
echo "<td>".$job->name."</td>";
}
echo "<td>".$person->likes($job)."</td>";
}
echo "</tr>";
}
echo "</table>";
This will give you a table like this:
Second, we need to create ALL permutations of jobs and persons. (actually we don't need to, but doing so, will show you the reason, why we don't need to!)
To create all permutations, we are using just the name of a person or job. (we can resolve the name back to the actual object later)
//build up all permutations
$personNames = array();
foreach ($persons AS $person){
$personNames[] = $person->name;
}
$jobNames = array();
foreach ($jobs AS $job){
$jobNames[] = $job->name;
}
$personsPerms = array();
pc_permute($personNames,$personsPerms);
$jobsPerms = array();
pc_permute($jobNames,$jobsPerms);
function pc_permute($items, &$result, $perms = array( )) {
if (empty($items)) {
$result[] = join('/', $perms);
} else {
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
pc_permute($newitems,$result, $newperms);
}
}
}
Now, we have 2 Arrays: All job permutations and all person permutations.
For the Example given above, the arrays will look like this (3 Elements each, makes 3*2*1=6 Permutations per Array):
Array
(
[0] => Max/Peter/Sam
[1] => Peter/Max/Sam
[2] => Max/Sam/Peter
[3] => Sam/Max/Peter
[4] => Peter/Sam/Max
[5] => Sam/Peter/Max
)
Array
(
[0] => New Classes/Theme change/Test Controller
[1] => Theme change/New Classes/Test Controller
[2] => New Classes/Test Controller/Theme change
[3] => Test Controller/New Classes/Theme change
[4] => Theme change/Test Controller/New Classes
[5] => Test Controller/Theme change/New Classes
)
Now, We can create a nXn Table, containing ALL Values of the overall satisfaction for ALL possible job allocations:
// debug: draw it:
echo "<h2>Total Happines of Combination (full join)</h2> ";
echo "<table border=1>";
$p=0;
echo "<tr>";
$row = 0;
$calculated = array();
foreach ($jobsPerms AS $jobComb){
$j=0;
$jobs_t = explode("/", $jobComb);
foreach ($personsPerms as $personComb){
if ($p++==0){
echo "<tr><td></td>";
foreach ($personsPerms as $n) {
echo "<td>".$n."</td>";
}
echo "</tr>";
}
if ($j++==0){
echo "<td>".$jobComb."</td>";
}
$persons_t = explode("/", $personComb);
$h = 0;
echo "<td>";
for ($i=0; $i< count($persons_t); $i++){
$h += $persons[$persons_t[$i]]->likes($jobs[$jobs_t[$i]]);
}
echo $h;
echo "</td>";
}
$col=0;
$row++;
echo "</tr>";
}
echo "</table>";
Lets call this matrix "M"
This Matrix contains a "lot" of double combinations: (a/b) TO (1/2) is equal to (b/a) to (2/1) etc...
After all: We simple can ignore:
Either Each row > 1
OR Each column > 1
Ignoring all Columns > 1:
echo "<h2>Total Happines of Combination (ignoring columns)</h2> ";
echo "<table border=1>";
$p=0;
echo "<tr>";
$row = 0;
$calculated = array();
foreach ($jobsPerms AS $jobComb){
$j=0;
$jobs_t = explode("/", $jobComb);
$col = 0;
$personComb = $personsPerms[0];
if ($p++==0){
echo "<tr><td></td>";
echo "<td>".$personsPerms[0]."</td>";
echo "</tr>";
}
if ($j++==0){
echo "<td>".$jobComb."</td>";
}
$persons_t = explode("/", $personComb);
$h = 0;
echo "<td>";
for ($i=0; $i< count($persons_t); $i++){
$h += $persons[$persons_t[$i]]->likes($jobs[$jobs_t[$i]]);
}
echo $h;
echo "</td>";
$col=0;
$row++;
echo "</tr>";
}
echo "</table>";
Output:
And there you go! In this Example (one of) the most satisfying Solution would be:
Max -> New Classes (+2)
Peter -> Test Controller (+2)
Sam -> Theme Change (+2)
-> Happiness: 6.
There are other, equal distributions as well.
Example: 6 persons / 6 jobs:
$persons = array(
"Max" => new Person("Max", "programing", "testing"),
"Peter" => new Person("Peter", "testing", "docu"),
"Sam" => new Person("Sam", "designing", "testing"),
"Jeff" => new Person("Jeff", "docu", "programing"),
"Fred" => new Person("Fred", "programing", "designing"),
"Daniel" => new Person("Daniel", "designing", "docu")
);
$jobs = array(
"New Classes" => new Job("New Classes", "programing"),
"Theme change" => new Job("Theme change", "designing"),
"Test Controller" => new Job("Test Controller", "testing"),
"Create Manual" => new Job("Create Manual", "docu"),
"Program more!" => new Job("Program more!", "programing"),
"Style the frontend" => new Job("Style the frontend", "designing")
);
results in (Persons: Max / Peter / Sam / Jeff / Fred / Daniel)
Assuming by "evenly distribute" you mean you know how many people must be assigned to each project, this is the weighted matching problem (aka "maximum cardinality bipartite matching"). Just treat each open position (rather than each job) as a node - so, a job with 3 positions will have three nodes.
The wikipedia article gives several solutions.
Pseudocode
for(n to number of jobs left)
{
job n = a random candidate
if(random candidate first preference == job n)
remove random candidate from list and remove job from list
}
if(jobs left)
{
for(n to number of jobs left)
for(i to number of candidates)
if(candidate first preference == job n)
{
job n = candidate i
remove candidate i from list and remove job n from list
}
else if(candidate second preference == job n)
{
job n = candidate i
}
}

Timepicker that removes times as they're selected (ajax)

I'm building a booking form for a moving business that uses a calendar combined with a start and end time. I built the timepicker with Formidable Pro, and it allows me to check "unique" on time fields which automatically removes them on the selected date. However it doesn't automatically remove the times from within the range between start and end times (ie: if someone chooses to rent a truck from 1am-3am I need 1am,2am,and 3am to be removed from future options but right now it only removes 1am and 3am) . I need to write ajax to remove the in-between times from the options. I'm not sure where to begin. This is the current ajax_time_ options function. Any push in the right direction would be appreciated.
function ajax_time_options(){
global $frmpro_settings, $frmdb, $wpdb;
//posted vars = $time_field, $date_field, $step, $start, $end, $date, $clock
extract($_POST);
$time_key = str_replace('field_', '', $time_field);
$date_key = str_replace('field_', '', $date_field);
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', trim($date)))
$date = FrmProAppHelper::convert_date($date, $frmpro_settings->date_format, 'Y-m-d');
$date_entries = FrmEntryMeta::getEntryIds("fi.field_key='$date_key' and meta_value='$date'");
$opts = array('' => '');
$time = strtotime($start);
$end = strtotime($end);
$step = explode(':', $step);
$step = (isset($step[1])) ? ($step[0] * 3600 + $step[1] * 60) : ($step[0] * 60);
$format = ($clock) ? 'H:i' : 'h:i A';
while($time <= $end){
$opts[date($format, $time)] = date($format, $time);
$time += $step;
}
if($date_entries and !empty($date_entries)){
$used_times = $wpdb->get_col("SELECT meta_value FROM $frmdb->entry_metas it LEFT JOIN $frmdb->fields fi ON (it.field_id = fi.id) WHERE fi.field_key='$time_key' and it.item_id in (". implode(',', $date_entries).")");
if($used_times and !empty($used_times)){
$number_allowed = apply_filters('frm_allowed_time_count', 1, $time_key, $date_key);
$count = array();
foreach($used_times as $used){
if(!isset($opts[$used]))
continue;
if(!isset($count[$used]))
$count[$used] = 0;
$count[$used]++;
if((int)$count[$used] >= $number_allowed)
unset($opts[$used]);
}
unset($count);
}
}
echo json_encode($opts);
die();
}

Error trying to exclude records with a JOIN to another object

In my code below, is there any way I can use the results in the object 'WasteRecordsExcluded' to join with searchResults, essentially excluding the WasteId's I don't want.
If I debug to the last line I get the error :
base {System.SystemException} = {"The query contains references to items defined on a different data context."}
Or if joining is impossible then i could change bHazardous from TRUE to FALSE and FALSE to TRUE and do some kind of 'NOT IN' comparison.
Going bananas with this one, anyone help? Kind Regards :
var allWaste = _securityRepository.FindAllWaste(userId, SystemType.W);
var allWasteIndicatorItems = _securityRepository.FindAllWasteIndicatorItems();
// First get all WASTE RECORDS
var searchResults = (from s in allWaste
join x in allWasteIndicatorItems on s.WasteId equals x.WasteId
where (s.Description.Contains(searchText)
&& s.Site.SiteDescription.EndsWith(searchTextSite)
&& (s.CollectedDate >= startDate && s.CollectedDate <= endDate))
&& x.EWC.EndsWith(searchTextEWC)
select s).Distinct();
var results = searchResults;
if (hazardous != "-1")
{
// User has requested to filter on Hazardous or Non Hazardous only rather than Show All
var WasteRecordsExcluded = (from we in _db.WasteIndicatorItems
.Join(_db.WasteIndicators, wii => wii.WasteIndicatorId, wi => wi.WasteIndicatorId, (wii, wi) => new { wasteid = wii.WasteId, wasteindicatorid = wii.WasteIndicatorId, hazardtypeid = wi.HazardTypeId })
.Join(_db.HazardTypes, w => w.hazardtypeid, h => h.HazardTypeId, (w, h) => new { wasteid = w.wasteid, hazardous = h.Hazardous })
.GroupBy(g => new { g.wasteid, g.hazardous })
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we);
// Now join the 2 object to eliminate all the keys that do not apply
results = results.Where(n => WasteRecordsExcluded.All(t2 => n.WasteId == t2.Key.wasteid));
}
return results;
Maybe something like this:
.....
var results = searchResults.ToList();
.....
.....
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we).ToList();
.....

Resources