Reputation: 4843
I have this data:
Array
(
[0] => Array
(
[name] => Hair Transplantation
[price] => € 1000 - 4000
)
[1] => Array
(
[name] => Rhinoplasty
[price] => € 2500
)
[2] => Array
(
[name] => Otoplasty
[price] => € 1000
)
)
I want to filter this array by price
key and, as a result, I want to be returned only one item, item with lowest price number.
Thank you!
Upvotes: 0
Views: 178
Reputation: 306
$data = [/* your data */];
uasort($data, function($a, $b) {
preg_match("/\d+/", $a['price'], $matchesA);
preg_match("/\d+/", $b['price'], $matchesB);
return (int)$matchesB[0] <=> (int)$matchesA[0];
});
$result = array_pop($data);
Added (08.08.2020) Because of vivek_23's comment, I added second solution:
$result = array_reduce($price, 'getMinimumPrice', null);
function getMinimumPrice(?array $itemA, array $itemB): array
{
if (is_null($itemA)) {
return $itemB;
}
return getPrice($itemA) < getPrice($itemB)
? $itemA
: $itemB;
}
function getPrice(array $item): int
{
preg_match("/\d+/", $item['price'], $matches);
return $matches[0];
}
And also I check the speed difference:
$primary = [
[
'name' => 'Hair Transplantation',
'price' => '€ 1000 - 4000',
],
[
'name' => 'Rhinoplasty',
'price' => '€ 2500',
],
[
'name' => 'Otoplasty',
'price' => '€ 1000',
],
/* ... 155 items */
];
function getMinimumPrice(?array $itemA, array $itemB): array
{
if (is_null($itemA)) {
return $itemB;
}
return getPrice($itemA) < getPrice($itemB)
? $itemA
: $itemB;
}
function getPrice(array $item): int
{
preg_match("/\d+/", $item['price'], $matches);
return $matches[0];
}
$timeRepeat = 1000;
$reduce = 0;
for ($i = 0; $i < $timeRepeat; $i++) {
$start = microtime(true);
$price = $primary;
array_reduce($price, 'getMinimumPrice', null);
$reduce += microtime(true) - $start;
}
$uasort = 0;
for ($i = 0; $i < $timeRepeat; $i++) {
$start = microtime(true);
$price = $primary;
uasort($price, function($a, $b) {
preg_match("/\d+/", $a['price'], $matchesA);
preg_match("/\d+/", $b['price'], $matchesB);
return (int)$matchesB[0] <=> (int)$matchesA[0];
});
array_pop($price);
$uasort += microtime(true) - $start;
}
print_r([
'uasort' => $uasort,
'reduce' => $reduce,
'difference' => round($uasort / $reduce, 12),
]);
My results:
Array (
[uasort] => 8.0096476078033
[reduce] => 2.1610336303711
[difference] => 3.706396557294
)
Upvotes: 4
Reputation: 19560
I don't like the data structure, as I noted in the comments on the question. It leads to string parsing which is not ideal.
I accomplished it, however, using
The following code will produce your desired result in the variable, $lowest_item
. If any of them have the same price (or same starting price), the first one that was defined will be the one returned (it could be edited to adjust which gets preference, though).
<?php
$data = [
[
'name' => 'Hair Transplantation',
'price' => '€ 1000 - 4000',
],
[
'name' => 'Rhinoplasty',
'price' => '€ 2500',
],
[
'name' => 'Otoplasty',
'price' => '€ 1000',
],
];
$lowest_item = array_reduce($data, function ($carry, $item) {
$return_to_next = null;
if (!$carry) {
$return_to_next = $item;
} else if ($carry['price'] === $item['price']) {
$return_to_next = $carry;
} else {
preg_match_all('/\d+/', $carry['price'], $carry_prices, PREG_PATTERN_ORDER);
preg_match_all('/\d+/', $item['price'], $item_prices, PREG_PATTERN_ORDER);
$carry_compare = min($carry_prices[0]);
$item_compare = min($item_prices[0]);
if ($carry_compare <= $item_compare) {
$return_to_next = $carry;
} else {
$return_to_next = $item;
}
}
return $return_to_next;
});
Upvotes: 1
Reputation: 910
Try this :
$items
is your base array.
$items = [
0 => [
"name" => "Hair Transplantation",
"price" => "€ 1000 - 4000"
],
1 => [
"name" => "Rhinoplasty",
"price" => "€ 2500"
],
2 => [
"name" => "Otoplasty",
"price" => "€ 1000"
]
];
$lowestPrice = PHP_INT_MAX;
$rightKey = -1;
foreach ( $items as $key => $item )
{
$clean = str_replace('€ ', '', $item['price']);
$chunks = explode('-', $clean);
if ( count($chunks) == 2 )
$price = floatval(trim($chunks[0]));
else
$price = floatval(trim($clean));
if ( $price < $lowestPrice )
{
$lowestPrice = $price;
$rightKey = $key;
}
}
$lowestItem = $items[$rightKey];
print_r($lowestItem);
EDIT: Regex version
$items = [
0 => [
"name" => "Hair Transplantation",
"price" => "€ 1000 - 4000"
],
1 => [
"name" => "Rhinoplasty",
"price" => "€ 2500"
],
2 => [
"name" => "Otoplasty",
"price" => "€ 1000"
]
];
$lowestPrice = PHP_INT_MAX;
$rightKey = -1;
foreach ( $items as $key => $item )
{
$matches = [];
if ( !preg_match('#([0-9\.]+) #', str_replace(',', '.', $item['price']), $matches) )
continue;
$price = floatval($matches[0]);
if ( $price < $lowestPrice )
{
$lowestPrice = $price;
$rightKey = $key;
}
}
$lowestItem = $items[$rightKey];
print_r($lowestItem);
Upvotes: 2
Reputation: 7675
$people = array(
0 => array(
'name' => 'Hair Transplantation',
'price' => '€ 1000 - 4000'
),
1=> array(
'name' => 'Rhinoplasty',
'price' => '€ 2500'
),
2=> array(
'name' => 'Otoplasty',
'price' => '€ 1000'
)
);
$price = array_map(function($value) {
if (strpos($value, '-') !== false) {
$value = explode("-", $value)[0];
}
list($symbol, $price) = sscanf($value,'%[^0-9]%s');
return intval($price);
}, array_column($people, 'price'));
$found_key = array_search(min($price),$price);
print_r($people[$found_key]) ;
Upvotes: 0