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?
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,
),
)
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;
?>
I'm trying to sort an array without using sort() function of php. I have tried so far and also google but unable to find result.
What I Need exactly
$arr = array(80, 90, 100, 10, 50, 3);
I want to sort this array in ascending. i can do it using sort() function but I want to do without using sort() function.
Are you looking for this:
<?php
$arr = array(80, 90, 100, 10, 50, 3);
for($a = 0; $a < count($arr); $a++) {
for($b = 0; $b < count($arr)-1; $b ++){
if($arr[$b] > $arr[$b+1]) {
$temp = $arr[$b+1];
$arr[$b+1]=$arr[$b];
$arr[$b]=$temp;
}
}
}
print_r($arr);
?>
Implementing QuickSort in PHP
or
Quicksort recursive.php
function quicksort( $array ) {
if( count( $array ) < 2 ) {
return $array;
}
$left = $right = array( );
reset( $array );
$pivot_key = key( $array );
$pivot = array_shift( $array );
foreach( $array as $k => $v ) {
if( $v < $pivot )
$left[$k] = $v;
else
$right[$k] = $v;
}
return array_merge(quicksort($left), array($pivot_key => $pivot), quicksort($right));
}
Usage :
$arr = array(80, 90, 100, 10, 50, 3);
$arr = quicksort($arr);
print_r($arr);
use this
$srtArray=array(80, 90, 100, 10, 50, 3);
for ($i=0; $i<count($srtArray); $i++) {
for ($j=0; $j<count($srtArray); $j++) {
// Compare two elements of array
if ($srtArray[$j] > $srtArray[$i]){
$tmp = $srtArray[$i];
$srtArray[$i] = $srtArray[$j];
$srtArray[$j] = $tmp;
}
}
}
//Print an array after sorting
for($i=0;$i<count($srtArray);$i++){
echo $srtArray[$i]."<br>\n";
}
You should use QuickSort because is practically the fastest way to sort an array of data. PHP's array sorting function sort() uses QuickSort. QuickSort is O(n log n).
<?php
$arr = array(80, 90, 100, 10, 50, 3);
function quicksort( $array ) {
if( count( $array ) < 2 ) {
return $array;
}
$left = $right = array( );
reset( $array );
$pivot_key = key( $array );
$pivot = array_shift( $array );
foreach( $array as $k => $v ) {
if( $v < $pivot )
$left[$k] = $v;
else
$right[$k] = $v;
}
return array_merge(quicksort($left), array($pivot_key => $pivot), quicksort($right));
}
$array = quicksort( $arr );
print_r($array);
Output:
Array
(
[0] => 3
[1] => 10
[2] => 50
[3] => 80
[4] => 90
[5] => 100
)
But if you can't use any built in function you can use this implementation of BubbleSort:
$arr = array(80, 90, 100, 10, 50, 3);
function bubbleSort ($items) {
$size = count($items);
for ($i=0; $i<$size; $i++) {
for ($j=0; $j<$size-1-$i; $j++) {
if ($items[$j+1] < $items[$j]) {
arraySwap($items, $j, $j+1);
}
}
}
return $items;
}
function arraySwap (&$arr, $index1, $index2) {
list($arr[$index1], $arr[$index2]) = array($arr[$index2], $arr[$index1]);
}
$array = bubbleSort( $arr );
print_r($array);
Reference:
http://pageconfig.com/post/implementing-quicksort-in-php
http://en.wikibooks.org/wiki/Algorithm_Implementation/Sorting/Quicksort#PHP
http://www.codecodex.com/wiki/Bubble_sort#PHP
Hope this will be the more optimized. Try this:
$arr = array(80, 90, 100, 10, 50, 3);
$count = count($arr);
for ($i = 0; $i < $count - 1; $i++ ) {
for ($j = $i+1; $j < $count; $j++ ) {
if ($arr[$i] > $arr[$j]) {
$temp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $temp;
}
}
}
print_r($arr);
$arr = array(80, 90, 100, 10, 50, 3,34,1,890);
for($i = 0; $i < count($arr); $i++) {
for($x = 0; $x < count($arr)-1; $x ++){
if($arr[$x] > $arr[$x+1]) {
$temp = $arr[$x+1];
$arr[$x+1]=$arr[$x];
$arr[$x]=$temp;
}
}
}
print_r($arr);
I want to get generate histogram data for the following array. array_count_values() would be great to use, except it just counts values for an exact value match. How can I elegantly do the same, but bundle values by a given step or interval?
$dataArray = array(385,515,975,1136,2394,2436,4051,4399,4484,4768,4768,4849,4856,4954,5020,5020,5020,5020,5020,5020,5020,5020,5020,5052,5163,5200,5271,5421,5421,5442,5746,5765,5903,5992,5992,6046,6122,6205,6208,6239,6310,6360,6416,6512,6536,6543,6581,6609,6696,6699,6752,6796,6806,6855,6859,6886,6906,6911,6923,6953,7016,7072,7086,7089,7110,7232,7278,7293,7304,7309,7348,7367,7378,7380,7419,7453,7454,7492,7506,7549,7563,7721,7723,7731,7745,7750,7751,7783,7791,7813,7813,7814,7818,7833,7863,7875,7886,7887,7902,7907,7935,7942,7942,7948,7973,7995,8002,8013,8013,8015,8024,8025,8030,8038,8041,8050,8056,8060,8064,8071,8081,8082,8085,8093,8124,8139,8142,8167,8179,8204,8214,8223,8225,8247,8248,8253,8258,8264,8265,8265,8269,8277,8278,8289,8300,8312,8314,8323,8328,8334,8363,8369,8390,8397,8399,8399,8401,8436,8442,8456,8457,8471,8474,8483,8503,8511,8516,8533,8560,8571,8575,8583,8592,8593,8626,8635,8635,8644,8659,8685,8695,8695,8702,8714,8715,8717,8729,8732,8740,8743,8750,8756,8772,8772,8778,8797,8828,8840,8840,8843,8856,8865,8874,8876,8878,8885,8887,8893,8896,8905,8910,8955,8970,8971,8991,8995,9014,9016,9042,9043,9063,9069,9104,9106,9107,9116,9131,9157,9227,9359,9471);
// if array_count_values accepted a step value I could do this:
print_r(array_count_values($dataArray,1000));
// expected result:
// array(1000 => 3, 2000 => 1, ... 10000 => 15);
// ^0-1000 ^[385,515,975]
What do you recommend?
In the event I have to loop through all values manually, is there an elegant way to round all values to a given interval?
$step = 1000;
$result = array_count_values(
array_map(
function ($value) use ($step) {
return (int) ceil($value / $step) * $step;
},
$dataArray
)
);
var_dump($result);
The rounding solution seems pretty straight forward:
$step_size = 10;
$data = array(10, 20, 24, 30, 35, 50);
foreach ($data as $index => $value) {
$data[$index] = round($value / $step_size) * $step_size;
}
// array(10, 20, 20, 30, 40, 50);
You can build the output directly to avoid mapping the entire data array just to make use of array_count_values(); below is a more generic implementation that allows the mapping to be done outside of the function itself:
function array_count_values_callback(array $data, callable $fn)
{
$freq = [];
foreach ($data as $item) {
$key = $fn($item);
$freq[$key] = isset($freq[$key]) ? $freq[$key] + 1 : 1;
}
return $freq;
}
print_r(array_count_values_callback($dataArray, function($item) {
return ceil($item / 1000) * 1000;
}));
Here is a simple solution where you loop through your $dataArray,
$step_size = 1000;
$histogramArray = array();
foreach ($dataArray as $v) {
$k = (int)ceil($v / $step_size) * $step_size;
if (!array_key_exists($k, $histogramArray)) $histogramArray[$k] = 0;
$histogramArray[$k]++;
}
And the output would be,
Array
(
[1000] => 3
[2000] => 1
[3000] => 2
[5000] => 8
[6000] => 21
[7000] => 25
[8000] => 46
[9000] => 110
[10000] => 15
)
So i've got an array that looks something like of:
Array ( [Safari] => 13 [Firefox] => 5 )
How do i a make a new array that looks like :
Array ( [Safari] => 72.2% [Firefox] => 27.7% )
using a neat php function?
thanks in advance.
You can use array_sum() to get the total, then iterate over the values returning the new value.
$total = array_sum($share);
foreach($share as &$hits) {
$hits = round($hits / $total * 100, 1) . '%';
}
CodePad.
If you have >= PHP 5.3 it can be a tad more elegant with an anonymous function.
$total = array_sum($share);
$share = array_map(function($hits) use ($total) {
return round($hits / $total * 100, 1) . '%';
}, $share);
CodePad.
$array=array ( 'Safari' => 13 ,'Firefox' => 5 );
$tot=array_sum($array);
foreach($array as $key=>$value){
$result[$key]=number_format(($value/$total)*100,1).'%';
}
print_r($result); //Array ( [Safari] => 72.2% [Firefox] => 27.7% )
Try this:
$array = Array ( 'Safari' => 13, 'Firefox' => 5 );
$total = array_sum($array); # total sum of all elements
$onePercent = $total / 100; # we want to know what value represents 1 percent
array_walk($array, create_function('&$v', '$v /= '.$onePercent.'; $v .= " %";')); # we walk through the array changing numbers to percents
var_export($array);
If you want to have your result in second array leaving $array not touched, you can use array_map instead of array_walk
You also might want to use sprintf to set precision of float values that represent percent, because my code would output:
array (
'Safari' => '72.2222222222 %',
'Firefox' => '27.7777777778 %',
)
It's not hard to figure out how to do it?
For PHP 5.3, you can do it like this:
$browsers = array('Safari' => 13, 'Firefox' => 5);
$browsers_proportioned = proportionalize($browsers);
function proportionalize ($arr) {
$total = array_sum($arr);
$names = array_map(
function($number) use ($total) { return number_format($number / $total * 100, 1) .'%'; },
$arr
);
return $names;
}
I personnally like when numbers add up to exactly 100 (not almost 100 like 99.99). So with the solution below, the last item uses the rest instead of being calculated like other items:
public static function getPercentagesByKeyValue(array $arr)
{
$ret = [];
$nbItems = count($arr);
$i = 1;
$sum = array_sum($arr);
foreach ($arr as $key => $number) {
$percent = round($number / $sum * 100, 2);
if ($i === $nbItems) {
$percent = 100 - (array_sum($ret));
}
$ret[$key] = $percent;
$i++;
}
return $ret;
}