I am attempting to find the closest product to the given budget
$array = array(
'productname1' => 5,
'productname2' => 10,
'productname3' => 15
)
$budget = 12;
I have tried using a function like the following to find the nearest value, but it only returns the number which is closest to the budget rather than the product name.
function closest($array, $number) {
sort($array);
foreach ($array as $a) {
if ($a >= $number) return $a;
}
return end($array);
}
I can't help but think there is a MUCH better implementation of this. Any help would be much appreciated.
foreach($array as $k => $v){ $diff[abs($v - $budget)] = $k; }
ksort($diff, SORT_NUMERIC);
$closest_key = current($diff);
var_dump($closest_key); // Product Name
var_dump($array[$closest_key]); // Product Cost
Prints:
string(12) "productname2" int(10)
Or as a function:
function closest($array, $price)
{
foreach($array as $k => $v){ $diff[abs($v - $price)] = $k; }
ksort($diff, SORT_NUMERIC);
$closest_key = current($diff);
return array($closest_key, $array[$closest_key]);
}
print_r(closest($array, $budget));
Prints:
Array ( [0] => productname2 // Product Name [1] => 10 // Product Price )
Both formats include only three steps:
EDIT: If you don't care about anything other than the single closest product, then a sort is overkill and a simple min()
function (like Emil used) would be a lot faster. For example:
function closest($array, $price)
{
foreach($array as $k => $v){ $diff[abs($v - $price)] = $k; }
$closest_key = $diff[min(array_keys($diff))];
return array($closest_key, $array[$closest_key]);
}
function closest($array, $number) {
sort($array);
foreach ($array as $name => $a) {
if ($a >= $number) return $name;
}
return end(array_keys($array));
}
The trick comes in on this line:
foreach ($array as $name => $a) {
Here you assign $name
to the array key and $a
to the array value. Since you want the name, return $name;
Also, if no match is found, do, end(array_keys($array)));
to get the name of the product, otherwise it will just spit out the value, which is not what you want.
You'll want to return the KEY, not the value:
function closest($array, $number) {
sort($array);
foreach ($array as $product=>$a) {
if ($a >= $number) return $product;
}
return $product;
}
Here's a functional way of doing it.
Implementation:
$diffs = array_map(function ($value) use ($budget) {
return abs($value - $budget);
}, $array);
$smallest = min($diffs);
$products = array_filter($array,
function ($value) use ($budget, $smallest) {
return abs($value - $budget) == $smallest;
});
$products
will now contain all the products which are closest to the budget.