-2

I have an associative array with 15 different companies and their stock prices, formatted as shown below:

$CloseStockPrice ('Business'=>50.5. 'Business two'=>100.5, .....)

I have found the average stock price:

$Average = (array_sum($CloseStockPrice)/count($CloseStockPrice));

The average ends up being 161.

But I now need to find the closest number (absolute terms) to that average value (161) within the associative array. I need to display the business and the stock value.

My most recent attempt:

function computeClosest(array $CloseStockPrice) 
{
    $closest = 161;
    
    for ($i = 161; $i < count($CloseStockPrice) ; $i++) 
    {
        if ($closest === 161) 
        {
            $closest = $CloseStockPrice[$i];
        } else if ($CloseStockPrice[$i] > 161 && $CloseStockPrice[$i] <= abs($closest)) 
        {
            $closest = $CloseStockPrice[$i];
        } else if ($CloseStockPrice[$i] < 161 && -$CloseStockPrice[$i] < abs($closest)) 
        {
            $closest = $CloseStockPrice[$i];
            return $closest;
        }
    }
}

Any suggestions?

Phil
  • 157,677
  • 23
  • 242
  • 245
coco
  • 3
  • 1
  • 2
    Please don't "yatta-yatta" your sample input data. Please create a [mcve] by using `var_export()` to express your array data. In accordance with PSR-12 guidelines, `else if` should be one word. It is not advisable to hardcode magic numbers (`161`) into your code. If this value is dynamic, set it as a variable and name that variable appropriately/intuitively. What happens if two businesses have `161`? What if one business is `160` and another is `162`? – mickmackusa Feb 23 '21 at 02:00

2 Answers2

1

While you loop through your array of business entries, cache the businesses with prices with the smallest absolute difference involving the average value.

While you might expect a single value in many cases, the fact that multiple qualifying businesses is possible means that you must keep an array of qualifying businesses for most accurate results.

A linear (single loop) process (O(n)) will outperform a sort algorithm (O(n log n)).
https://stackoverflow.com/q/56506410/2943403

Code: (Demo)

$closeStockPrice = [
    'A' => 50,
    'B' => 155,
    'C' => 75,
    'D' => 245,
    'E' => 300,
    'F' => 100,
    'G' => 153,
];

$average = array_sum($closeStockPrice) / count($closeStockPrice);

$bestDistances = [];
foreach ($closeStockPrice as $business => $price) {
    $distance = abs($average - $price);
    $current = current($bestDistances);
    if (!$bestDistances || $current > $distance) {
        $bestDistances = [$business => $distance];  // new best distance
    } elseif ($current === $distance) {
        $bestDistances[$business] = $distance;  // push business with same distance
    }
}
var_export([
    'average' => $average,
    'bestDistances' => $bestDistances,
    'bestBusinessPrices' => array_intersect_key($closeStockPrice, $bestDistances)
]);

Output:

array (
  'average' => 154,
  'bestDistances' => 
  array (
    'B' => 1,
    'G' => 1,
  ),
  'bestBusinessPrices' => 
  array (
    'B' => 155,
    'G' => 153,
  ),
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
0

I'm not here to agree with the stock market, but you may want to know what they're up to:

<?php
class AvgSorter{
  public $sorted = [];
  public function sort($array){
    $s = &$this->sorted; array_splice($s, 0);
    foreach($array as $k => $v){
      $s[$k] = $v;
    }
    $avg = array_sum($s)/count($s);
    uasort($s, function($a, $b) use($avg){
      $a = abs($a-$avg); $b = abs($b-$avg);
      if($a === $b){
        return 0;
      }
      return $a > $b ? 1 : -1;
    });
    return $this;
  }
  public function firstKey(){
    return array_keys($this->sorted)[0];
  }
  public function firstValue(){
    return $this->sorted[$this->firstKey()];
  }
  public function lastKey(){
    return array_keys($this->sorted)[count($this->sorted)-1];
  }
  public function lastValue(){
    return $this->sorted[$this->lastKey()];
  }
}
$array = ['business 1'=>1000.32, 'business 2'=>5.15, 'business 3'=>10.22, 'business 4'=>4.01, 'business 5'=>10.82, 'business 6'=>3.12, 'business 7'=>1.01];
$avgSorter = new AvgSorter; $firstKey = $avgSorter->sort($array)->firstKey();
$firstValue = $avgSorter->firstValue(); $lastKey = $avgSorter->lastKey(); 
$lastValue = $avgSorter->lastValue();
$test = 'first key:'.$firstKey.', first value:'.$firstValue.', last key:'.$lastKey.', last value:'.$lastValue;
?>
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
StackSlave
  • 10,613
  • 2
  • 18
  • 35
  • This answer is missing its educational explanation. I am particularly interested in hearing what `array_slice($array, 0)` does. As of PHP8: `Deprecated: uasort(): Returning bool from comparison function is deprecated` Please do not write multiple declarations on a single line of code -- the vertical space saving is not worth the impact on code readability. Depending on the PHP version, your snippet will give different results when there is a tie on price distance from the average. https://3v4l.org/lhmfg – mickmackusa Feb 23 '21 at 03:49
  • @mickmackusa, I was dumping the array without `=` assigment, in case there is an association with the array. – StackSlave Feb 23 '21 at 04:30
  • Please address all of the concerns in my earlier comment. – mickmackusa Feb 23 '21 at 04:33