Laravel sort collection by multi fields - laravel

I stucked with a collection sorting in laravel based on different situations.
For simplicity here is an example collection:
1;
pmt: 1
thm: 1
customerFriendly: false
2;
pmt: 1
thm: 1
customerFriendly: true
3;
pmt: 2
thm: 4
customerFriendly: true
I need to sort this collection first based on the pmt value. Lowest first.
If there are same pmt values than I need a second sorting based on the thm value.
After that if there is maybe a same thm than I need to sort it again by the customer boolean field.
So based on the above example the final sorted list should be 2,1,3
As far as I get I can sort the list first by pmt and if same pmt-s found by thm, but I cant sort it by customerFriendly.
Here is my code:
$pmtDuplicated = $this->checkDuplicates($transformedLoans, 'pmt');
if ($pmtDuplicated) { //If we found same pmt-s sort by thm also
$secondSort = $transformedLoans->sortBy(function ($item) {
return $item->pmt . '-' . $item->thm;
})->values();
$thmDuplicatesInSecondSort = $this->checkDuplicates($secondSort, 'thm'); //Check again for same thm
if ($thmDuplicatesInSecondSort) { //If we found same thm sort by customerFriendly also
return $secondSort->sortBy('customerFriendly')->values();
} else {
return $secondSort;
}
} else {
return $transformedLoans->sortBy('pmt')->values();
}
Someone maybe can help me out? Thank you.

I found the solution, and I leave it here if for someone is a help later.
Instead of this section:
if ($thmDuplicatesInSecondSort) { //If we found same thm sort by customerFriendly also
return $secondSort->sortBy('customerFriendly')->values();
}
I needed to use this:
if ($thmDuplicatesInSecondSort) { //Ha van THM alapján is egyezés akkor fogyasztóbarát alapján is rendezzen
return $secondSort->sortBy(function ($item) {
return $item->customerFriendly === false ? 1 : 0;
})->values();
}

Related

How to sort a collection in Laravel

I doing sortBy function to sort but i can't use it as sorted by For.
$this->journey->journey_item = $this->journey->journey_items->sortBy('activation_date');
dump($journey_items); //// sorted list
for($i = 0;$i < Count($this->journey->journey_item);$i++){
dump("#".$i." ".$this->journey->journey_item[$i]->activation_date);
}
When it entered in For, it becomes as unsorted.
Where am i doing wrong ?
What can i do ?
Also, I have created a new collection and tried to equalize it, again it didn't
Try with foreach. when you use collection sort it'll sort your array not key.. as I see you're using key [$i].
Use foreach
foreach($this->journey->journey_item as $journey_item){
dump($journey_item);
}
Or you use as below.
$this->journey->journey_item = $this->journey->journey_items->sortBy(function ($journey_item) {
return $journey_item->activation_date;
});

How do I use TimSort to sort by multiple fields?

I have implemented TimSort but I really need to be able to sort by different fields. E.g. sort by field 2, then 1, then 3. I know in general terms how to do this, sort by the next field if the previously given fields to sort by are equal, but I'm looking for a solution that has more detail and in particular for TimSort.
The fact that you sort using several fields has an influence on the comparing function alone, not on the implementation of the sorting algorithm you use.
To sort objects, you need to be able to compare them. A simple way to do so is to implement a function isSmaller, that takes two objects as arguments, and returns true if the first is smaller than the second.
The function isSmaller can look like this with the criteria you gave:
function isSmaller(object1, object2) -> boolean {
if object1.field2 < object2.field2 {
return true
} else if object1.field2 > object2.field2 {
return false
} else { // equality on first criterion -> check the second
if object1.field1 < object2.field1 {
return true
} else if object1.field1 > object2.field1 {
return false
} else { // equality again -> check 3rd criterion
if object1.field2 < object2.field3 {
return true
} else if object1.field2 > object2.field3 {
return false
} else { // equality on all criteria -> can return true or false
return true
}
}
}
}
All you have to do then, is to use it to compare your objects in your implementation of Timsort.

get Biggest collection in a collection of collection

I have a Collection of collection.
I would like to get the biggest collection inside the collection.
I wrote a function that works well, but I'm pretty sure it can be done much quicker:
private function getMaxFightersByEntity($userGroups): int
{
$max = 0;
foreach ($userGroups as $userGroup) { // $userGroup is another Collection
if (count($userGroup) > $max) {
$max = count($userGroup);
}
}
return $max;
}
I'm quite sure there is a better way managing collection, but don't really know it.
Anyone has a better solution???
You can sort the collection by the count of the inner collections, and then just take the first item (largest group).
// sortByDesc: sort the groups by their size, largest first
// first: get the first item in the result: the largest group
// count: get the size of the largest group
return $userGroups
->sortByDesc(function ($group) {
return $group->count();
})
->first()
->count();
It won't be "quicker" than your current solution in execution time, but it is written to take advantage of the functions provided by collections.

Get column number from column name

Is there any method to get the column number from the column name?
I can only retrieve the column name, and I need the column number for getCellMeta.
Thanks
Made this function that solved my problem:
function GetColFromName(name)
{
var n_cols = $editorTableContainer.handsontable('countCols');
var i = 1;
for (i=1; i<=n_cols; i++)
{
if (name.toLowerCase() == $editorTableContainer.handsontable('getColHeader', i).toLowerCase()) {
return i;
}
}
return -1; //return -1 if nothing can be found
}
This is almost what I required but not quite as I needed the column prop. I couldn't find the answer anywhere so thought I would add this to the thread that helped me.
instead of using 'getColHeader' use 'colToProp'.
Use propToCol("Column Name"). This returns the column's index.

Multidimensional data lookup

I have a collection of tuples of N values. A value may be a wildcard (matches any value), or a concrete value. What would be the best way to lookup all tuples in the collection matching a specific tuple without scanning the entire collection and testing items one by one?
E.g. 1.2.3 matches 1.*.3 and *.*.3, but not 1.2.4 or *.2.4.
What data structure am I looking for here?
I'd use a trie to implement this. Here's how I would construct the trie:
The data structure would look like:
Trie{
Integer value
Map<Integer, Trie> tries
}
To insert:
insert(tuple, trie){
curTrie = trie
foreach( number in tuple){
nextTrie = curTrie.getTrie(number)
//add the number to the trie if it isn't in there
if(nextTrie == null){
newTrie = new Trie(number)
curTrie.setTrie(number, newTrie)
}
curTrie = curTrie.getTrie(number)
}
}
To get all the tuples:
getTuples(tuple, trie){
if(head(tuple) == "*"){
allTuples = {}
forEach(subTrie in trie){
allTuples.union(getTuples(restOf(tuple), subTrie))
forEach(partialTuple in allTuples){
partialTuple = head(tuple)+partialTuple
}
}
return allTuples
}
if(tuple == null)
return {trie.value}
if(trie.getTrie(head(tuple)) == null)
raise error because tuple does not exist
allTuples = {}
allTuples.union(getTuples(restOf(tuple), trie.getTrie(head(tuple))
forEach(partialTuple in allTuples){
partialTuple = head(tuple)+partialTuple
}
return allTuples
}

Resources