1

I have an array of StdClass Objects and want to return the "partner_code" with the minimum value for key "price". So for this example I would like to return partner_code "AC" as it is the partner with the lowest price. I tried using array_reduce, but I'm not sure what I'm doing wrong. Any help would be appreciated. Please note I am not looking to SORT this array. I just want to move the subarray containing AC (because it hold the lowest price) to the top - not sorting everything by price

Input Array:

Array
    (
    [0] => stdClass Object
        (
            [name] => Budget
            [partner_code] => BU
            [price] => 365.36
            [tier] => 1
        )

    [1] => stdClass Object
        (
            [name] => Avis
            [partner_code] => AV
            [price] => 449.71
            [tier] => 1
        )

    [2] => stdClass Object
        (
            [name] => E-Z
            [partner_code] => EZ
            [price] => 270.56
            [tier] => 2
        )

    [3] => stdClass Object
        (
            [name] => Sixt
            [partner_code] => SX
            [price] => 280.52
            [tier] => 2
        )

    [4] => stdClass Object
        (
            [name] => Alamo
            [partner_code] => AL
            [price] => 345.13
            [tier] => 2
        )

    [5] => stdClass Object
        (
            [name] => Advantage
            [partner_code] => AD
            [price] => 357.61
            [tier] => 2
        )

    [6] => stdClass Object
        (
            [name] => Enterprise
            [partner_code] => ET
            [price] => 364.46
            [tier] => 2
        )

    [7] => stdClass Object
        (
            [name] => ACE
            [partner_code] => AC
            [price] => 186.53
            [tier] => 3
        )

    [8] => stdClass Object
        (
            [name] => Fox
            [partner_code] => FX
            [price] => 265.25
            [tier] => 3
        )

    [9] => stdClass Object
        (
            [name] => Payless
            [partner_code] => ZA
            [price] => 380.47
            [tier] => 3
        )

    [10] => stdClass Object
        (
            [name] => Dollar
            [partner_code] => ZR
            [price] => 385.99
            [tier] => 3
        )

    [11] => stdClass Object
        (
            [name] => Thrifty
            [partner_code] => ZT
            [price] => 385.99
            [tier] => 3
        )

    [12] => stdClass Object
        (
            [name] => Silvercar
            [partner_code] => SC
            [price] => 424.10
            [tier] => 3
        )

    [13] => stdClass Object
        (
            [name] => National
            [partner_code] => NA
            [price] => 448.82
            [tier] => 3
        )

    [14] => stdClass Object
        (
            [name] => Hertz
            [partner_code] => HZ
            [price] => 487.33
            [tier] => 3
        )
    )

Code:

 array_reduce($this->results->companies, function($a,$b) {
        echo "Prices: " . $a->price . "<br>";
        return $a->price < $b->price ? (string)$a->partner_code : (string)$b->partner_code;
 });
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • I would just sort the array by `price` and then get the first or last element based on the sort direction, eg `usort($this->results->companies, function($a, $b) { return $a->price - $b->price; }); $pc = $this->results->companies[0]->partner_code;` – Phil Sep 01 '17 at 05:08
  • 1
    Try this one https://eval.in/853582 – Sahil Gulati Sep 01 '17 at 05:17
  • *"Please note I am not looking to SORT this array"* <- it seems you are. How else would you determine the first entry by price? – Phil Sep 01 '17 at 05:37
  • Sorry let me clarify - I'd the following sort "AC" (lowest price), "BU", "AV", "EZ", SX"...so really it's just moving only AC with the lowest price to the top - not sorting everything by price – Michael Alterio Sep 01 '17 at 05:42

3 Answers3

1
usort($array, function($a, $b) {
        return ($a->price - $b->price) ;
});

echo $array[0]->partner_code;
Akshay Hegde
  • 16,536
  • 2
  • 22
  • 36
  • Numeric sort functions are much easier if you just return *"comparableA - comparableB"* – Phil Sep 01 '17 at 05:19
  • Or `$comparableA <=> $comparableB` – Scopey Sep 01 '17 at 05:22
  • @Scopey nice (needs PHP 7 though). Hardly worth it for numeric operations though. A simple subtraction would surely be computationally cheaper – Phil Sep 01 '17 at 05:23
0

If you really don't want to sort the array but instead use array_reduce, do so by reducing the array to one of its elements. Then you can get the partner_code property for that element.

For example

array_reduce($this->results->companies, function($lowest, $company) {
    // $lowest will be null on the first iteration
    return $lowest === null || $company->price < $lowest->price ?
        $company : $lowest;
})->partner_code;
Phil
  • 157,677
  • 23
  • 242
  • 245
  • Thanks Phil. If I wanted to return the position that the lowest price is in, how can I do that using the array_reduce function here? So for this example, position "7". – Michael Alterio Sep 01 '17 at 05:54
  • @MichaelAlterio You could use something like `array_search` to find the index of the element in the original array but now you're changing the requirements of your question. What is it **exactly** that you're trying to do? – Phil Sep 01 '17 at 06:37
0

This method will not sort the entire array. It will pull out the subarray with the lowest price and set it as the first element. I could have nested some of the functions to make it more compact (1-liner), but that would have damaged readability.

Code: (Demo)

$results=[
    (object)["name"=>"Budget","partner_code"=>"BU","price"=>"365.36","tier"=>"1"],
    (object)["name"=>"Avis","partner_code"=>"AV","price"=>"449.71","tier"=>"1"],
    (object)["name"=>"E-Z","partner_code"=>"EZ","price"=>"270.56","tier"=>"2"],
    (object)["name"=>"Sixt","partner_code"=>"SX","price"=>"280.52","tier"=>"2"],
    (object)["name"=>"Alamo","partner_code"=>"AL","price"=>"345.13","tier"=>"2"],
    (object)["name"=>"Advantage","partner_code"=>"AD","price"=>"357.61","tier"=>"2"],
    (object)["name"=>"Enterprise","partner_code"=>"ET","price"=>"364.46","tier"=>"2"],
    (object)["name"=>"ACE","partner_code"=>"AC","price"=>"186.53","tier"=>"3"],
    (object)["name"=>"Fox","partner_code"=>"FX","price"=>"265.25","tier"=>"3"],
    (object)["name"=>"Payless","partner_code"=>"ZA","price"=>"380.47","tier"=>"3"],
    (object)["name"=>"Dollar","partner_code"=>"ZR","price"=>"385.99","tier"=>"3"],
    (object)["name"=>"Thrifty","partner_code"=>"ZT","price"=>"385.99","tier"=>"3"],
    (object)["name"=>"Silvercar","partner_code"=>"SC","price"=>"424.10","tier"=>"3"],
    (object)["name"=>"National","partner_code"=>"NA","price"=>"448.82","tier"=>"3"],
    (object)["name"=>"Hertz","partner_code"=>"HZ","price"=>"487.33","tier"=>"3"]
];
$min=min(array_column($results,'price'));  // find the minimum value
$index=array_search($min,array_column($results,'price'));  // find the index of the subarray containing min value
$pulled=array_splice($results,$index,1);  // extract the subarray and preserve it as $pulled
$new_results=array_merge($pulled,$results);  // set $pulled as first element
var_export($new_results);

...okay, okay, here's the one-liner: var_export(array_merge(array_splice($results,array_search(min(array_column($results,'price')),array_column($results,'price')),1),$results));

Output:

array (
  0 => 
  stdClass::__set_state(array(
     'name' => 'ACE',
     'partner_code' => 'AC',
     'price' => '186.53',
     'tier' => '3',
  )),
  1 => 
  stdClass::__set_state(array(
     'name' => 'Budget',
     'partner_code' => 'BU',
     'price' => '365.36',
     'tier' => '1',
  )),
  2 => 
  stdClass::__set_state(array(
     'name' => 'Avis',
     'partner_code' => 'AV',
     'price' => '449.71',
     'tier' => '1',
  )),
  3 => 
  stdClass::__set_state(array(
     'name' => 'E-Z',
     'partner_code' => 'EZ',
     'price' => '270.56',
     'tier' => '2',
  )),
  4 => 
  stdClass::__set_state(array(
     'name' => 'Sixt',
     'partner_code' => 'SX',
     'price' => '280.52',
     'tier' => '2',
  )),
  5 => 
  stdClass::__set_state(array(
     'name' => 'Alamo',
     'partner_code' => 'AL',
     'price' => '345.13',
     'tier' => '2',
  )),
  6 => 
  stdClass::__set_state(array(
     'name' => 'Advantage',
     'partner_code' => 'AD',
     'price' => '357.61',
     'tier' => '2',
  )),
  7 => 
  stdClass::__set_state(array(
     'name' => 'Enterprise',
     'partner_code' => 'ET',
     'price' => '364.46',
     'tier' => '2',
  )),
  8 => 
  stdClass::__set_state(array(
     'name' => 'Fox',
     'partner_code' => 'FX',
     'price' => '265.25',
     'tier' => '3',
  )),
  9 => 
  stdClass::__set_state(array(
     'name' => 'Payless',
     'partner_code' => 'ZA',
     'price' => '380.47',
     'tier' => '3',
  )),
  10 => 
  stdClass::__set_state(array(
     'name' => 'Dollar',
     'partner_code' => 'ZR',
     'price' => '385.99',
     'tier' => '3',
  )),
  11 => 
  stdClass::__set_state(array(
     'name' => 'Thrifty',
     'partner_code' => 'ZT',
     'price' => '385.99',
     'tier' => '3',
  )),
  12 => 
  stdClass::__set_state(array(
     'name' => 'Silvercar',
     'partner_code' => 'SC',
     'price' => '424.10',
     'tier' => '3',
  )),
  13 => 
  stdClass::__set_state(array(
     'name' => 'National',
     'partner_code' => 'NA',
     'price' => '448.82',
     'tier' => '3',
  )),
  14 => 
  stdClass::__set_state(array(
     'name' => 'Hertz',
     'partner_code' => 'HZ',
     'price' => '487.33',
     'tier' => '3',
  )),
)

I think this is a leaner method generating the same/desired result: (Demo)

$min=$results[0]->price;  // set initial/default min value
$index=0; // set initial/default index
foreach($results as $i=>$a){
    if($a->price<$min){  // if a lower price...
        $min=$a->price;  // store new $min
        $index=$i;  // stor new $index
    }
}
$results=array_merge($results,array_splice($results,$index,1));  // extract lowest and move to front of array
var_export($results);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136