0

I've got this PHP array:

<?php 

$cities = [
    'amsterdam' => $amsterdam,
    'prague'    => $prague,
    'lisboa'    => $lisboa
];

$amsterdam = [
    65 => [
        'table'     => Object
        'something' => false,
        'data'      => [
            'foo'    => 'boo',
            'price'   => 100
        ]
    ],
    173 => [
        'table'     => Object
        'something' => false,
        'data'      => [
            'foo'    => 'hoo',
            'price'   => 2500
        ]
    ],
    ...
];

$prague    = [
    132 => [
        'table'     => Object
        'something' => false,
        'data'      => [
            'foo'    => 'boo',
            'price'   => 2100
        ]
    ],
    956 => [
        'table'     => Object
        'something' => false,
        'data'      => [
            'foo'    => 'hoo',
            'price'   => 2500
        ]
    ],
    ...
];

$lisboa    = [
    175 => [
        'table'     => Object
        'something' => false,
        'data'      => [
            'foo'    => 'boo',
            'price'   => 6500
        ]
    ],
    64 => [
        'table'     => Object
        'something' => false,
        'data'      => [
            'foo'    => 'hoo',
            'price'   => 20
        ]
    ],
    ...
];

?>

and I need to sort it by the subarray value ['data']['price'] so the output is like this:

<?php
    $cheapest_cities [
        'lisboa'    => $lisboa,    // because 64->data->price is 20
        'amsterdam' => $amsterdam, // beacuse 65->data->price is 100
        'prague'    => $prague     // bacause 132->data->price is 2100
    ];
?>

I tried several usort combinations, but the problem is, that i never know what the subarray index will be (65, 173, 132, 956, 175, 64) in my example.

Do you have any idea how to sort it?

The data comes from database:

<?php

        $amsterdam  = $this->getTable()->where(['package_id' => [1,2,3]])->order('package_id')->fetchPairs('id');
        $lisboa     = $this->getTable()->where(['package_id' => [4,5]])->order('package_id')->fetchPairs('id');
        $prague     = $this->getTable()->where(['package_id' => [6]])->order('package_id')->fetchPairs('id');

        return [
            'amsterdam'     => $amsterdam,
            'lisboa'        => $lisboa,
            'prague'        => $prague,
        ];

?>

Thank you

Café
  • 98
  • 1
  • 7

2 Answers2

1

I would start by making a new array, which has the smallest price of every city as value

For this I use an array_map function which reduces the $items to the price with array_reduce

$map_prices = function($n) { 
    $reduce_smallest_price = function($carry, $item) {
        return $item['data']['price'] < $carry 
                                      ? $item['data']['price'] 
                                      : $carry; 
    };
    return array_reduce($n, $reduce_smallest_price, INF); 

};

$cities_price = array_map($map_prices, $cities);

asort($cities_price);

I use this prices array to sort the original array with uksort

uksort($cities, function($a, $b) { 
    global $cities_price; 
    return strnatcmp($cities_price[$a], $cities_price[$b]);

});

Here is a live example on 3v4l: https://3v4l.org/8B9VN

yunzen
  • 32,854
  • 11
  • 73
  • 106
0

Don't use usort as it will remove your keys. Use uasort.

Just a quick idea: Inside the callback function of uasort you could search the minimum of your item e.g. via array_reduce.

array_reduce($city, function($carry, $item) {
    return $carry === 0 ? $item['data']['price'] : min($carry, $item['data']['price']);
}, 0);

This snippet gets the minimum of a city array. Then it should be easy to compare the values.

Full example:

function getMinimumPrice($cityArray) {
    return array_reduce($cityArray, function($carry, $item) {
        return $carry === 0 ? $item['data']['price'] : min($carry, $item['data']['price']);
    }, 0);
}

uasort($cities, function($city1, $city2) {
    $priceCity1 = getMinimumPrice($city1);
    $priceCity2 = getMinimumPrice($city2);

    return $priceCity1 <=> $priceCity2;
});
Kévin Bibollet
  • 3,573
  • 1
  • 15
  • 33
Sindhara
  • 1,423
  • 13
  • 20
  • While this works and is a good answer, it has it's flaws. You should add a caching mechanism for the results of the `array_reduce` calls. Just imagine you have 100 cities with 1000 prices. The array_reduce function will be called perhaps one million times – yunzen Mar 11 '19 at 10:53