It's fun with sorting today! Sigh. I have a big collection of eloquent models that need to be grouped together in the array by one parameter, and ordered in those 'clumps' based on another parameter. This might be hard to explain :(
$master is a collection of Eloquent results, I'm not sure how to write them out here, looping over this I can access all the models functions / relationships
$master = [];
These have 2 properties that need to be the basis for a sort, example of the properties below
//Object 1
$master->carry = 0;
$master->section = 'red';
//Object 2
$master->carry = 1;
$master->section = 'blue';
//Object 3
$master->carry = 0;
$master->section = 'blue';
I want to sort a massive collection of these so that each $master->section is in one 'clump' in the array and inside that 'clump' the $master->carry=0 products are listed last.
From the example above I'd expect Object1, Object3, Object2
I've tried a few different $master->sort() and $master->sortBy() things, but each new sort throws off the old sort :(
I've got the code below currently, which groups up all the colors, but it doesn't order them based on $master->carry yet
$order = array('red', 'blue', 'green');
$master = $master->sort(function ($a, $b) use ($order) {
$pos_a = array_search($a->sectionheader, $order);
$pos_b = array_search($b->sectionheader, $order);
return $pos_a - $pos_b;
});
As I understood, you want to sort your collection the following way:
sort by section in the order stored in $order array
within section move the elements with carry = 0 to the end
You need to pass a function that would implement such logic to $master collection. This function should take 2 arguments (2 elements of collection), compare them and return:
0 if elements are equal
1 if the first element is greater than the second element
-1 if the first element is smaller than the second element
In your case the following callback should work:
$master = $master->sort(function ($a, $b) use ($order) {
// get order of first element's section
$pos_a = array_search($a->section, $order);
// get order of second element's section
$pos_b = array_search($b->section, $order)
// if sections are different the value of carry doesn't matter
// as element's sections are enough to determine which of them is larger
if ($pos_a != $pos_b) {
return $pos_a - $pos_b;
}
// carry values are equal, so consider elements equal
if ($a->carry == $b->carry) {
return 0;
}
if (!$a->carry) {
// if $a->carry is equal to 0 it should be put at the end, so after $b
return 1;
}
if (!$b->carry) {
// if $b->carry is equal to 0 it should be put at the end, so after $a
return -1;
}
// otherwise elements can be considered equal
return 0;
});
Related
I want to sort php object array in which i have to consider two different keys while sorting, if value of two users is same then consider another key for those values.
given array example
[{'id':'1','total_number':'90','previous_number':'75'},
{'id':'2','total_number':'80','previous_number':'91'},
{'id':'3','total_number':'80','previous_number':'84'},
{'id':'4','total_number':'80','previous_number':'96'},
{'id':'5','total_number':'95','previous_number':'80'}
]
Result array:
[{'id':'5','total_number':'95','previous_number':'80'},
{'id':'1','total_number':'90','previous_number':'75'},
{'id':'4','total_number':'80','previous_number':'96'},
{'id':'2','total_number':'80','previous_number':'91'},
{'id':'3','total_number':'80','previous_number':'84'}
]
You can use a custom sort function to achieve the desired result with the help of usort function in PHP https://www.php.net/manual/en/function.usort.php
// custom sort function
function mySort($a, $b) {
// is total_number same?
if ($a->total_number === $b->total_number) {
// use previous_number to sort
if ($a->previous_number === $b->previous_number) {
return 0;
}
// sort desc
return $a->previous_number > $b->previous_number ? -1 : 1;
}
// sort desc
return $a->total_number > $b->total_number ? -1 : 1;
}
// call the function
usort($array, 'mySort');
I want to skip, some element from collection
$post_one = Post_one::all();
$post_two = Post_two::all();
$posts = collect();
if($post_one){
foreach($post_one as $post){
$posts->push($post);
}
}
if($post_two){
foreach($post_two as $post){
$posts->push($post);
}
}
//now i want to skip n=3, element form the collection of posts
$posts = $posts->sortBy('created_at')-<skip(3)->take(3);//does not work
error::Method skip does not exist.
To combine both records you can use merge method with flatten, i,e
$posts = $post_one->flatten(1)->merge($post_two)->sortBy('created_at');
Then you use filter to get the right result:
$filtered = $posts->filter(function ($post, $key) {
return $key > 2;
});
This skips the first 3 since the key starts from 0...n.
Or you can just slice the collection:
$nextthree = $posts->slice(3, 3);
This skips 3 and takes the next 3 from the collection. You can access the original collections $posts.
At this point the index of the collection is preserved, but to reset it to start from 0...n just use values() method i.e:
$nextthree = $posts->slice(3, 3)->values();
You can do it with forPage() method.
Like this:
$posts = $posts->forPage($currentPage, $perPage);
Documentation
i have an array of objects like this : http://pastebin.ca/3217309
i want to sort this array to objects with come first then others sort by date
currently I'm using this to sort array
function cmp($a, $b)
{
return strcmp($a->date, $b->date);
}
usort($data, "cmp");
and works good but it only sort array by date and i want to in ordered array objects with pin=1 come first then other objects come after pins.
i hope my question is clear,sorry for bad english !
If you want to sort after an other criteria, you should just add the condition to your sort function:
if ($a->pin != $b->pin) return $a->pin == 1 ? -1 : 1;
this condition only applies for $items with unequal pin properties. Combine your old compare function with this one would result in the following
function cmp($a, $b) {
if ($a->pin != $b->pin) return $a->pin == 1 ? -1 : 1;
return strcmp($a->date, $b->date);
}
I'm a little stuck on something that usually is quite straight forward. I need to sort records from a hasMany relationship into a custom order based on a certain value and an 'sort order' array.
My code below doesn't work because I'm passing uSort() a eloquent collection and I'm not sure how to get around it.
$go = $this->hasMany('Product')->orderBy('colour','DESC');
$order = array('RED', 'GREEN', 'BLUE', 'YELLOW');
usort($go, function ($a, $b) use ($order) {
$pos_a = array_search($a->colour, $order);
$pos_b = array_search($b->colour, $order);
return $pos_a - $pos_b;
});
return $go;
Maybe I'm missing some amazing laravel magic helper, but I'm stuck. Any thoughts or advice would be much appreciated!
Cheers
The usort equivalent for Collection is the sort() method. It takes a callback as a parameter and returns the sorted collection.
So in your case, the solution is:
$go = $go->sort(function ($a, $b) use ($order) {
$pos_a = array_search($a->colour, $order);
$pos_b = array_search($b->colour, $order);
return $pos_a - $pos_b;
});
Your sorting will be applied only after you get the result while here $go = $this->hasMany('Product')->orderBy('colour','DESC'); you are just getting an instance of a class which will return can return your result if you apply a get method on it.
For your purpose you have to use sortBy method of laravel collections after you get the result of your data you can find more (laravel Collection sortBy() method) & here is a similar question answer for you https://stackoverflow.com/a/28202985
I need to sort an array, I've done this before but it has been easy because the array had numbers or letters to sort in ascedning/descending or alphabetical order.. In this case i have an array of which each element has 3 values, eg:
array[0]=code=1234
=description='example array'
=orderCode=P
array[1]=code=1235
=description='example array1'
=orderCode=A
.
.
.
Now i need to order theese reading the orderCode value in this order: P,I,B,C,A,S,D.
The way i thought of getting arround it was to add another value to the array and to something like:
if($array[$c]['orderCode'] == 'P')
$array[$c]['newOrderCode'] = 0;
if($array[$c]['orderCode'] == 'I')
$array[$c]['newOrderCode'] = 1;
if($array[$c]['orderCode'] == 'B')
$array[$c]['newOrderCode'] = 2;
or a switch case and then order it by the new value. This would work, but my question is, is there a function I can pass the array to and an orderring string or something?
Thank you,
James
In php 5.3 and above you can use usort with a closure.
$order = array('P','I','B','C','A','S','D');
usort($array, function ($a, $b) use ($order){
return array_search($a["orderCode"], $order) - array_search($b["orderCode"], $order);
});
prior to that you have to create a sorter function
function orderCode_sorter($a, $b){
$order = array('P','I','B','C','A','S','D');
return array_search($a["orderCode"], $order) - array_search($b["orderCode"], $order);
}
usort($array, "orderCode_sorter");
use function user defined and choise sort by key or value you need see all list function here: http://www.php.net/manual/en/array.sorting.php