0

I have the following json:

$data = '{"code":"08261",
          "currency":"EUR", 
          "packs":[ {"amount":0.05,"measure":"g","price":73.0}, 
                    {"amount":0.1,"measure":"g","price":108.0}, 
                    {"amount":0.25,"measure":"g","price":154.0}, 
                    {"amount":0.5,"measure":"g","price":296.0}, 
                    {"amount":1.0,"measure":"g","price":394.0}, 
                    {"amount":2.5,"measure":"g","price":771.0}, 
                    {"amount":5.0,"measure":"g","price":1142.0}, 
                    {"amount":10.0,"measure":"g","price":1693.0}]}'; 

I can get the value of code and currency as follows:

// Option 1: through the use of an array.
$jsonArray = json_decode($data,true);

$code =  $jsonArray['code'];

// Option 2: through the use of an object.
$jsonObj = json_decode($data);

$code = $jsonObj->code;

How can I get the price for the following packs where the:

  1. amount is '1.0' and measure is 'g'
  2. amount is '5.0' and measure is 'g'
  3. amount is '10.0' and measure is 'g'
adam78
  • 9,668
  • 24
  • 96
  • 207

2 Answers2

2

If you convert the json into nested arrays (passing true to the $associative parameter of json_decode, you can then use array_filter to filter the packs to find the values you want:

$data = '{"code":"08261",
          "currency":"EUR", 
          "packs":[ {"amount":0.05,"measure":"g","price":73.0}, 
                    {"amount":0.1,"measure":"g","price":108.0}, 
                    {"amount":0.25,"measure":"g","price":154.0}, 
                    {"amount":0.5,"measure":"g","price":296.0}, 
                    {"amount":1.0,"measure":"g","price":394.0}, 
                    {"amount":2.5,"measure":"g","price":771.0}, 
                    {"amount":5.0,"measure":"g","price":1142.0}, 
                    {"amount":10.0,"measure":"g","price":1693.0}]}'; 

function get_price($data, $amount, $measure) {
    $values = array_filter($data['packs'], function ($a) use ($measure, $amount) {
        return $a['amount'] == $amount && $a['measure'] == $measure;
    });
    if (count($values)) return reset($values)['price'];
    return 0;
}

$data = json_decode($data, true);

echo get_price($data, 1.0, 'g') . PHP_EOL;
echo get_price($data, 5.0, 'g') . PHP_EOL;
echo get_price($data, 10.0, 'g') . PHP_EOL;

Output:

394
1142
1693

For those stuck with versions of PHP that don't support anonymous functions, it's simpler just to use a foreach loop over $data['packs']:

function get_price($data, $amount, $measure) {
    foreach ($data['packs'] as $pack) {
        if ($pack['amount'] == $amount && $pack['measure'] == $measure) {
            return $pack['price'];
        }
    }
    return 0;
}
Nick
  • 138,499
  • 22
  • 57
  • 95
  • thanks for the solution. I'm stuck with php 5.2 so I've had to use global variables to pass the parameters for the call back. I'm still getting an error on the following `reset($values)['price']` in php 5.2. Do you know how to rewrite this line so that it work in php 5.2? – adam78 Sep 08 '22 at 15:25
  • @adam78 you really should upgrade! PHP5 has been out of support a long time and likely has all sorts of security holes in it. In the meantime though I've edited the answer with a solution that will work on 5.2 – Nick Sep 08 '22 at 23:29
0

You can use array_filter like this:

$jsonObj = json_decode($data);
$result = array_filter(
    $jsonObj->packs,
    fn($pack) => $pack->amount === 1.0 && $pack->measure === 'g'
);

That uses an arrow function. If you generalize that solution, implementing a function:

function filterPacks($packs, $amount, $measure) {
    return array_filter(
        $packs,
        fn($pack) => $pack->amount === $amount && $pack->measure === $measure
    );
}

$jsonObj = json_decode($data);
print_r(filterPacks($jsonObj->packs, 5.0, 'g'));

According to a comment, you have "to use global variables to pass the parameters for the call back" because you're "stuck with php 5.2". You can do this in PHP 5.2.0:

function filterPacks($packs, $amount, $measure) {
    $filtered = array();
    foreach ($packs as $pack) {
        if ($pack->amount === $amount && $pack->measure === $measure) {
            $filtered []= $pack;
        }
    }
    return $filtered;
}

$jsonObj = json_decode($data);
print_r(filterPacks($jsonObj->packs, 10.0, 'g'));

Notice there are pitfalls when comparing floating points.

Pedro Amaral Couto
  • 2,056
  • 1
  • 13
  • 15