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

4
  • And what's the point in knowing index? Commented Mar 11, 2019 at 10:16
  • Where do get these values from? It might be easier to change the source. Commented Mar 11, 2019 at 10:19
  • @u_mulder: Well, I tried this: stackoverflow.com/questions/16582086/…, but i have random numbers instead of 'family_data' key Commented Mar 11, 2019 at 10:29
  • @yunzen: They come from database: Commented Mar 11, 2019 at 10:30

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

Comments

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;
});

1 Comment

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.