Как отфильтровать ассоциативный массив php по ключам и значениям? - PullRequest
0 голосов
/ 06 августа 2020

У меня есть эти данные:

Array
(
    [0] => Array
        (
            [name] => Hair Transplantation
            [price] => € 1000 - 4000
        )

    [1] => Array
        (
            [name] => Rhinoplasty
            [price] => € 2500
        )

    [2] => Array
        (
            [name] => Otoplasty
            [price] => € 1000
        )

)

Я хочу отфильтровать этот массив по ключу price, и в результате я хочу, чтобы мне возвращали только один элемент, элемент с наименьшей ценой. 1005 *

Спасибо!

Ответы [ 4 ]

4 голосов
/ 06 августа 2020
$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);

Добавлено (08.08.2020) Из-за комментария vivek_23 я добавил второе решение:

    $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];
    }

А также проверяю разницу в скорости:

$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),
]);

Мои результаты :

Array (
       [uasort] => 8.0096476078033
       [reduce] => 2.1610336303711
       [difference] => 3.706396557294
)
2 голосов
/ 06 августа 2020

Попробуйте следующее:

$items - ваш базовый массив.

$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

$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);
1 голос
/ 06 августа 2020

Мне не нравится структура данных, как я отмечал в комментариях к вопросу. Это приводит к синтаксическому анализу строки, который не идеален.

Я выполнил это, однако, используя

Следующие code выдаст желаемый результат в переменной $lowest_item. Если любой из них имеет одинаковую цену (или одинаковую начальную цену), будет возвращена первая определенная цена (хотя ее можно отредактировать, чтобы настроить предпочтение).

<?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;
});
0 голосов
/ 06 августа 2020
$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]) ;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...