moo moo
moo moo

Reputation: 484

How to get the lowest value from a JSON array with PHP

I am trying to loop through a JSON multidimensional array and get the lowest distance value for each shop and print it along with the location_id value.

I can't get any further than what I have here. I've tried a million options by searching through stackoverflow but just can't figure out what I'm doing wrong.

My JSON data is like this:

$json = '{
  "shops": [
   {
      "shop_id": "100",
          "locations": [
                { "location_id": "100_1", "distance": "10.3" },
                { "location_id": "100_2", "distance": "15.2" }
          ]
    },
    {
      "shop_id": "101",
          "locations": [
                { "location_id": "101_1", "distance": "19.3" },
                { "location_id": "101_2", "distance": "12.4" }
          ]
    }]
}';

Right now, the code I have is:

// Decode the JSON data
$json_data = json_decode($json,true);

// Do a foreach loop
foreach($json_data['shops'] as $shops){

echo $shops['shop_id'].', ';

// Currently prints:
// 101, 102 ,

// But I need it to print:
// 100_1 -> 10.3, 101_2 -> 12.4

}

I tried putting another foreach loop into the existing one but that just prints a 1.

How do I achieve that? I can't wrap my head around it. I need the lowest distance value printed for each of the ['shop_id']['locations']

Upvotes: 0

Views: 919

Answers (2)

Progrock
Progrock

Reputation: 7485

You can use sub-loops, to try and pick out the lowest distance. Easier to follow the code and to construct a resulting array:

<?php
$json = '{
  "shops": [
   {
        "shop_id": "100",
        "locations": [
            { "location_id": "100_1", "distance": "10.3" },
            { "location_id": "100_2", "distance": "15.2" }
        ]
    },
    {
        "shop_id": "101",
        "locations": [
            { "location_id": "101_1", "distance": "19.3" },
            { "location_id": "101_2", "distance": "12.4" }
        ]
    }]
}';

$data = json_decode($json, true);

$min_distances = [];
foreach($data['shops'] as $shop)
{
    $distance = null;
    foreach($shop['locations'] as $location)
    {
        if(is_null($distance) || $location['distance'] < $distance)
        {
            $distance = $location['distance'];
            $location_id  = $location['location_id'];
        }
    }
    $min_distances[] = [
        'shop_id'=>$shop['shop_id'], 
        'distance'=>$distance, 
        'location_id'=>$location_id
    ];
}
var_dump($min_distances);

Output:

 array(2) {
[0]=>
array(3) {
    ["shop_id"]=>
    string(3) "100"
    ["distance"]=>
    string(4) "10.3"
    ["location_id"]=>
    string(5) "100_1"
}
[1]=>
array(3) {
    ["shop_id"]=>
    string(3) "101"
    ["distance"]=>
    string(4) "12.4"
    ["location_id"]=>
    string(5) "101_2"
}
}

Upvotes: 0

Nick
Nick

Reputation: 147176

You can use array_column to extract all the distances for a particular shop and then use min on that array to get the lowest value. To also get the location, we then use array_search to find the minimum key with that value and use that to get the appropriate location_id for the store:

foreach($json_data['shops'] as $shops) {
    $distances = array_column($shops['locations'], 'distance');
    $locations = array_column($shops['locations'], 'location_id');
    $min = min($distances);
    $location = array_search($min, $distances);
    echo $locations[$location] . ' -> ' . $min . "\n";
}

Output:

100_1 -> 10.3 
101_2 -> 12.4

Demo on 3v4l.org

Update

As @Andreas has pointed out in the comments, we can use the third parameter to array_column to get an array of distances with their location_id as the key. We can then sort the array and use current and key to get the minimum distance and corresponding location:

foreach($json_data['shops'] as $shops) {
    $distances = array_column($shops['locations'], 'distance', 'location_id');
    asort($distances);
    echo key($distances) . ' -> ' . current($distances) . "\n";
}

Output:

100_1 -> 10.3 
101_2 -> 12.4

Demo on 3v4l.org

Upvotes: 5

Related Questions