how to map collection in php laravel - php

i want return data if a < b then a = b, if using foreach i have to make empty array first and parsing data to te empty array, how if record i much, that take time
public function getDepreciation(){
$values = $this->repository->getDepreciation();
$data = [];
foreach($values as $value){
if($value->depresiation_per_month > $value->balance_value){
$value->depresiation_per_month = $value->balance_value;
}
array_push($data,$value->depresiation_per_month,$value->balance_value);
}
return $data;
}
is there is simple code than my above, since i have to make relist many array

You can convert this array in a Collection then handle it easier by using the transform method.
First you have to create the collection using your array Create Collection
$values = collect($values);
Then you can iterate over the collection using the transform method and apply your logic Transform Method
Finally you have to convert your collection into an array using the toArray method toArray Method
I hope this works for you

Related

How to save values outside of a Laravel each loop

I am not fully understanding Laravel Collections.
I need to know how save external values while iterating through a Lavavel Collection using the each(function(n){})
For example:
static public myFunction($laravelCollection) ={
$arr=[];
$laravelCollection->each(function($a){
$arr[]=$a
});
return $arr
}
...
$exampleArr = SomeClass::myFunction($aCollection);
var_dump($exampleArr);
//desired results: the var_dump of the collection
It seams that $arr inside of the each function is local to the function. How can I accomplish the above? I realize that if it was NOT a static function, I could simply use a $this->arr instead, but I need to do the above using a static function.
Modifying a variable inside a laravel collection, you will have to use use() method with reference &.
$arr = [];
$laravelCollection->each(function($a) use(&$arr) {
$arr[] = $a;
});
Or even better, since you are simply converting your collection into an array:
$arr = $laravelCollection->toArray();
Check out the collection docs.

sortBy returns object instead of array

I have this code
$list = Elements::where('list_id', $id)->with('visitors')->get()->sortBy(function($t)
{
return $t->visitors->count();
});
return json_encode($list);
This code returns object, not array. How I can change it?
You should add ->values() if you want an actual JSON array in the end.
As you might add other manipulations like filters and transforms, I'd call ->values() at the very last moment:
return json_encode($list->values());
The reason for using ->values() over other options is that it resets the array keys. If you try returning some associative array (like ['name' => 'Roman'] or even [1 => 'item', 0 => 'other']), it will always get encoded as an object. You need to have a plain array (with sequential integer keys starting at 0) to avoid unexpected things that filtering and sorting will do.
You just need to call the ->all() Collection method, so
$list = Elements::where('list_id', $id)->with('visitors')->get()->sortBy(function($t)
{
return $t->visitors->count();
}
)->all();
this differs to the ->toArray() method because it will also cast to array also the object inside the collection, and not only the colletion itself (actually ->all() won't cast anything, it will just return the elements inside the collection)
$list = Elements::where('list_id', $id)->with('visitors')->get();;
This code return Collection Instance. $collection->sortBy(...); also is Collection instance. For get array in Collection you must be use or ->toArray(), or ->all()
In your case you can use
$list = Elements::where('list_id', $id)->with('visitors')->get()->sortBy(function($t) {
return $t->visitors->count();
})->toArray();

Laravel merge multiple collections and sort by corresponding datetime field

I have multiple collections merging into one, then sorting that one by datetime to ultimately create a timeline between the collections.
Heres the catch, the datetime columns to sort are different names.
Is there anything I can do to make this cleaner - possibly attach the foreach loop with the ->merge? Looks ugly with the foreach loop. note: code below works but I feel it's a lazy way out and might be slow with more items in the collection.
// Create timeline, sortby creation datetimes.
$TimelineItems = collect();
$TimelineItems = $Appointments->merge($lead->SalesResult);
foreach ($TimelineItems as $key => $TimelineItem) {
if(!empty($TimelineItem->appointment_created)) {
$TimelineItems[$key]->created_at = $TimelineItem->appointment_created;
}
if(!empty($TimelineItem->salesresult_created_timestamp)) {
$TimelineItems[$key]->created_at = $TimelineItem->salesresult_created_timestamp;
}
}
$TimelineItems = $TimelineItems->sortByDesc('created_at');
dd($TimelineItems);
The best solution would probably be to standardize your model objects to use standard date stamp fields - then you wouldn't need to transform them.
Failing that, you could use each() or transform():
// Create timeline, sortby creation datetimes.
$TimelineItems = collect();
$AppointmentTemps = collect($Appointments);
$SalesResultTemps = $lead->SalesResult;
$TimelineItems = $AppointmentTemps
->merge($SalesResultTemps)
->transform( function ($item) {
if(!empty($item->appointment_created)) {
$item->created_at = $item->appointment_created;
}
if(!empty($item->salesresult_created_timestamp)) {
$item->created_at = $item->salesresult_created_timestamp;
}
return $item;
})
->sortByDesc('created_at');
dd($TimelineItems);
The transform method iterates over the collection and calls the given callback with each item in the collection. The items in the collection will be replaced by the values returned by the callback:
See the docs for the transform() collection method for reference.

why foreach print just one value in laravel?

I have a method:
public function winnerDetails()
{
$winners = DB::table('winners')->get();
//dd($winners);
foreach ($winners as $winner) {
$qrMainId = $winner->qrdetails_id;
}
dd($qrMainId);
}
dd($winners); returns to value of array but when i use foreach its returns one value. How can i get who value returns with foreach loop?
dd($winners) output:
and dd($qrMainId); return one value 44. But it should return another value of array 35; Thanks in advance.
To get array of ID's use
foreach ($winners as $winner) {
$qrMainId[]= $winner->qrdetails_id;
For just value use
$qrMainId='';
foreach ($winners as $winner) {
$qrMainId.= $winner->qrdetails_id;
If you want to accomplish this task in a Laravel way use the pluck method to map the array for the key that you want
<?php
public function winnerDetails()
{
$winnersId = DB::table('winners')->get()->pluck('qrdetails_id');
dd($winnersId);
}
I think you are not leveraging the power of Laravel here. Obviously, I don't know what you are trying to do but here are some pointers.
You should probably be making a model for the winners table now models in Laravel return Collections as does the DB facade you are using now. Now the Collection class contains alot of usefull helpers like pluck
At this point it becomes as easy as Winner::all()->pluck('id') and you got yourself an array of id's.
And if you would like to get them comma seperated or anything like that you can use the implode
And you would get Winner::all()->implode('id',',');
$qrMainId is a variable not an array.
It is modified in the foreach during every loop.
So your code has always the last element of the array.
Use an array to collect values like
$qrMainId[] = $winner->qrdetails_id;
or sql select directly the field you want.

What Interface to implement so an object behave like an array [duplicate]

I have a class called Collection which stores objects of same type.
Collection implements array interfaces: Iterator, ArrayAccess, SeekableIterator, and Countable.
I'd like to pass a Collection object as the array argument to the array_map function. But this fails with the error
PHP Warning: array_map(): Argument #2 should be an array
Can I achieve this by implementing other/more interfaces, so that Collection objects are seen as arrays?
The array_map() function doesn't support a Traversable as its array argument, so you would have to perform a conversion step:
array_map($fn, iterator_to_array($myCollection));
Besides iterating over the collection twice, it also yield an array that will not be used afterwards.
Another way is to write your own map function:
function map(callable $fn)
{
$result = array();
foreach ($this as $item) {
$result[] = $fn($item);
}
return $result;
}
Update
Judging by your use-case it seems that you're not even interested in the result of the map operation; therefore it makes more sense to use iterator_apply().
iterator_apply($myCollection, function($obj) {
$obj->method1();
$obj->method2();
return true;
});
array_map wants, as the name suggests, arrays. It's not called iterator_map after all. ;)
Apart from iterator_to_array(), which produces a potentially large temporary array, there's no trick to make iterable objects work with array_map.
The Functional PHP library has a map implementation which works on any iterable collection.
If you're not interested in creating a new array that is a function mapped over the original array, you could just use a foreach loop (because you implement Iterator).
foreach($item in $myCollection) {
$item->method1();
$item->method2();
}
if you actually want to use map, then I think you'll have to implement your own. I would suggest making it a method on Collection, eg:
$mutatedCollection = $myCollection->map(function($item) {
/* do some stuff to $item */
return $item;
});
I would ask yourself if you really want to use map or do you really just mean foreach
I came up with the following solution:
//lets say you have this iterator
$iterator = new ArrayIterator(array(1, 2, 3));
//and want to append the callback output to the following variable
$out = [];
//use iterator to apply the callback to every element of the iterator
iterator_apply(
$iterator,
function($iterator, &$out) {
$current = $iterator->current();
$out[] = $current*2;
return true;
},
array($iterator, &$out) //arguments for the callback
);
print_r($out);
This way, you can generate an array without iterating twice as you would to with the approach like:
$iterator = new ArrayIterator(array(1,2,3));
$array = iterator_to_array($iterator); //first iteration
$output = array_map(function() {}, $array); //second iteration
Good luck!
I just stumbled upon this question and I managed to cast the collection to an array to make it work:
array_map($cb, (array) $collection);
disclaimer For the original question this might not be a suitable option but I found the question while looking to solve a problem which I solved with this solution. I would recommend using a custom iterator map where possible/viable.
another option is to do something like this:
foreach($collection as &$item) {
$item = $cb($item);
}
which will mutate the underlying collection.
EDIT:
It has been pointed out that casting to an array can have unwanted side effects. It would be better to add a method to your collection to return the array from the iterator, and traverse that, or otherwise add a map method which accepts a callback and run a loop on the underlying iterator.

Categories