Sort results by closest value

Recommended Posts

Hey all, I'm facing a problem way over my knowledge right now. Big problem and tight deadline :(

Basically is this:

```\$percentuale = 20; // percentace

if (\$input->get->lunghezze) {
\$lunghezza = \$sanitizer->selectorValue(\$input->get->lunghezze);
\$input->whitelist->lunghezze = \$lunghezza;
\$tolleranza = (\$percentuale / 100) * \$lunghezza; // calculating the tolerance
\$val_up = floor(\$lunghezza + \$tolleranza); // tolerance up
\$val_down = floor(\$lunghezza - \$tolleranza); // tolerance down
\$selector .= "variante_prodotto.lunghezza=\$lunghezza, ";
\$tolerance .= "variante_prodotto.lunghezza>=\$val_down, ";
\$tolerance .= "variante_prodotto.lunghezza<=\$val_up, ";
}
\$tolerance .= "template=prodotto_alimentare, sort=variante_prodotto.lunghezza";
/* I want to sort the result from the closest to \$lunghezza,
but now they are sorted by the smallest to the greatest. */
\$matches = \$pages->find(\$selector);
\$with_tolerance = \$pages->find(\$tolerance);
\$insieme = \$pages->find("id=\$matches|\$with_tolerance");

foreach(\$insieme as \$product) {
//etc...
}  ```

I'm outputting a series of product which has a particular length (\$lunghezza) and also other products which are contained inside a particular tolerance (\$with_tolerance).

How can i sort the results (\$insieme) from the closest to \$lunghezza onwards? Right now they are sorted by the smallest to the greatest.

Hope to have some feedback from you. Thanks!

Share on other sites

5 hours ago, 3fingers said:

How can i sort the results (\$insieme) from the closest to \$lunghezza onwards?

I don't think it will be possible to achieve this sort via SQL in the \$pages->find() selector - you'll have to do it via PHP in memory, so hopefully you don't have too many results.

I don't know what sort of field variante_prodotto is so you may need to adapt this if it holds multiple values but here is the general idea:

```foreach(\$insieme as \$product) {
// Here you might need to cast \$product.variante_prodotto.lunghezza and \$lunghezza to int or float as appropriate
// Get difference as an absolute value as store as a custom property on \$product
\$product->difference = abs(\$product.variante_prodotto.lunghezza - \$lunghezza);
}
// Sort by custom property
\$insieme->sort('difference');
foreach(\$insieme as \$product) {
// ...
}```

Share on other sites

Thanks @Robin S, I'm trying to get my head around it.

```if (\$input->get->lunghezze) {
\$lunghezza = \$sanitizer->selectorValue(\$input->get->lunghezze);
\$input->whitelist->lunghezze = \$lunghezza;
\$tolleranza = (\$percentuale / 100) * \$lunghezza;
\$val_up = floor(\$lunghezza + \$tolleranza);
\$val_down = floor(\$lunghezza - \$tolleranza);

//SORT DELTA UP
\$lun_unsorted_up = \$pages->find("variante_prodotto.lunghezza>=\$lunghezza,variante_prodotto.lunghezza<=\$val_up");
foreach(\$lun_unsorted_up as \$lun){
\$lun->delta = abs(\$lun->variante_prodotto[0]->lunghezza - \$lunghezza);
}
\$lun_sorted_up = \$lun_unsorted_up->sort('delta');

//SORT DELTA DOWN
\$lun_unsorted_down = \$pages->find("variante_prodotto.lunghezza<=\$lunghezza,variante_prodotto.lunghezza>=\$val_down");
foreach(\$lun_unsorted_down as \$lun){
\$lun->delta = abs(\$lun->variante_prodotto[0]->lunghezza - \$lunghezza);
}
\$lun_sorted_down = \$lun_unsorted_down->sort('delta');
}```

I have more input->get variables, and I'm applying the same concept. At a point in time I "join" all the array I get like this:

`\$insieme = \$pages->find("id=\$lun_sorted_up|\$lun_sorted_down"); // and so on...`

All good...but, if i put a "limit=20" to the selector (for pagination):

`\$insieme = \$pages->find("id=\$matches|\$lun_sorted_up|\$lun_sorted_down, limit=20");`

The sorting order is completely gone! Why?

Share on other sites

Two problems...

1. As soon as you do this...

5 minutes ago, 3fingers said:

\$insieme = \$pages->find("id=\$lun_sorted_up|\$lun_sorted_down");

...you are going to lose any sorting that has been applied those PageArrays. Using \$pages->find() and matching by ID doesn't preserve the order that the IDs are supplied in. Aside: \$pages->getByID() does preserve the order of supplied IDs but you can't set a limit for pagination so it won't help you here.

2.

7 minutes ago, 3fingers said:

if i put a "limit=20" to the selector (for pagination)

You can't use pagination in the normal sense with this kind of sorting. Normally you use pagination for performance reasons, to avoid loading the entire result set into memory, but in this case you need the entire result set in memory so you can foreach over them to set the custom sort. That's why I said that hopefully you don't have too many results. If you have thousands of results you probably can't use this technique. If you want pagination for some other reason besides performance then you could look at something like saving the sorted PageArray to \$session and then getting slices of that PageArray on each numbered results page. This post will get you started on that (substitute the sorted PageArray for images in that example):

Share on other sites

Thanks @Robin S, I'm going to put on my black ninja belt and solve this puzzle.

• 1
Share on other sites

Hi,

I'm not so good in PHP ...

In a website I want to sort result using foreach, this is the code:

`\$profi = \$pages->get("/professionisti/")->children('limit=4, sort=date'); `

My question is: if I want to change the order, from the latest to the oldest or from the oldest .. what I have to write?

Thanks a lot

Share on other sites

2 hours ago, angelo, italy said:

My question is: if I want to change the order, from the latest to the oldest or from the oldest .. what I have to write?

sort=-date will sort by date from latest to oldest 🙂

Share on other sites

• 3 months later...

Hi @Robin S, I've sent you a PM, let me know, thanks.

Create an account

Register a new account