I have an array of dates that contains many dates.
I have placed all dates on the graph in php, but there is not enough space on the graph.
I want to make the dates short (i.e samples) to be placed on the graph.
For example
array=(1,2,3,4,5,6,7,8,9,7,8,9,6,5);
After short and sampling it should be
1,4,8,8,5
You can loop through array and add nth values to new array that You can use in Your graph.
You can use modulo on array keys for that and use ratio of values to number of results You whant.
$new_array = array();
$array = array(1,2,3,4,5,6,7,8,9,7,8,9,6,5);
$array_count = count($array);
$number_of_results = 5; // number of results you whant
$ratio = ceil($array_count / $number_of_results);
foreach ($array as $key => $val) {
if ( $key % $ratio == 0 ) {
$new_array[] = $val;
}
}
Related
I'm trying to combine numbers in an array by adding them so that the max value can only by 30.
For example, this is my array:
array(10,30,10,10,15);
After combining the numbers in the array to items with a max value 30, the result should be:
array(30,30,15);
How to achieve this?
I'm trying to combine numbers in an array by adding them so that the
max value can only by 30
So, when you combine numbers, you can achieve the lowest possible set of values in your array and also make sure that max value remains 30 by:
First, sort them.
Second, keeping adding elements to sum till you are about to get a sum > 30.
Third, once an element can no longer be added to a sum, add the current sum in your array and make the current element as the new sum.
Code:
<?php
$arr = array(10,30,10,10,15);
sort($arr);
$res = [];
$curr_sum = 0;
foreach($arr as $each_value){
if($curr_sum + $each_value <= 30) $curr_sum += $each_value;
else{
$res[] = $curr_sum;
$curr_sum = $each_value;
}
}
$res[] = $curr_sum;
print_r($res);
Demo: https://3v4l.org/BYhuE
Update: If order of the numbers matters, seeing your current output, you could just use rsort() to show them in descending order.
rsort($res);
$total = array_sum(array(10,30,10,10,15)); //assign sum totals from orignal array
$maxValue = 30; //assign max value allowed in array
$numberOfWholeOccurancesOfMaxValue = floor($total/$maxValue);
$remainder = $total%$maxValue;
//build array
$i=0;
while ( $i < $numberOfWholeOccurancesOfMaxValue ){
$array[] = $maxValue;
$i++;
}
$array[] = $remainder;
print_r($array);
You can loop only once to get this,
$temp = array(10,30,10,10,15);
natsort($temp); // sorting to reduce hustle and complication
$result = [];
$i = 0;
$maxValue = 30;
foreach($temp as $v){
// checking sum is greater or value is greater or $v is greater than equal to
if(!empty($result[$i]) && (($result[$i]+$v) > $maxValue)){
$i++;
}
$result[$i] = (!empty($result[$i]) ? ($result[$i]+$v) : $v);
}
print_r($result);
Working demo.
I believe finding most space-optimized/compact result requires a nested loop. My advice resembles the firstFitDecreasing() function in this answer of mine except in this case the nested loops are accessing the same array. I've added a couple of simple conditions to prevent needless iterations.
rsort($array);
foreach ($array as $k1 => &$v1) {
if ($v1 >= $limit) {
continue;
}
foreach ($array as $k2 => $v2) {
if ($k1 !== $k2 && $v1 + $v2 <= $limit) {
$v1 += $v2;
unset($array[$k2]);
if ($v1 === $limit) {
continue 2;
}
}
}
}
rsort($array);
var_export($array);
By putting larger numbers before smaller numbers before processing AND by attempting to add multiple subsequent values to earlier values, having fewer total elements in the result is possible.
See my comparative demonstration.
I believe #Clint's answer is misinterpreting the task and is damaging the data by summing all values then distributing the max amounts in the result array.
With more challenging input data like $array = [10,30,5,10,5,13,14,15,10,5]; and $limit = 30;, my solution provides a more dense result versus #nice_dev's and #rahul's answers.
I'm using the following code to retrieve the highest 3 numbers from an array.
$a = array(1,2,5,10,15,20,10,15);
arsort($a, SORT_NUMERIC);
$highest = array_slice($a, 0, 3);
This code correctly gives me the highest three numbers array(20,15,10); however, I'm interested in getting the highest 3 numbers including the ones that are identical. In this example, I'm expecting to get an array like array(10, 10, 15, 15, 20)
Might be simpler but my brain is tired. Use arsort() to get the highest first, count the values to get unique keys with their count and slice the first 3 (make sure to pass true to preserve keys):
arsort($a, SORT_NUMERIC);
$counts = array_slice(array_count_values($a), 0, 3, true);
Then loop those 3 and fill an array with the number value the number of times it was counted and merge with the previous result:
$highest = array();
foreach($counts as $value => $count) {
$highest = array_merge($highest, array_fill(0, $count, $value));
}
You can use a function like this:
$a = array(1,2,5,10,15,20,10,15); //-- Original Array
function get3highest($a){
$h = array(); //-- highest
if(count($a) >= 3){ //-- Checking length
$c = 0; //-- Counter
while ($c < 3 || in_array($a[count($a)-1],$h) ){ //-- 3 elements or repeated value
$max = array_pop($a);
if(!in_array($max,$h)){
++$c;
}
$h[] = $max;
}
sort($h); //-- sorting
}
return $h; //-- values
}
print_r(get3Highest($a));
Of course you can improve this function to accept a dinamic value of "highest" values.
The below function may be usefull
$a = array(1,2,5,10,15,20,10,15);
function getMaxValue($array,$n){
$max_array = array(); // array to store all the max values
for($i=0;$i<$n;$i++){ // loop to get number of highest values
$keys = array_keys($array,max($array)); // get keys
if(is_array($keys)){ // if keys is array
foreach($keys as $v){ // loop array
$max_array[]=$array[$v]; // set values to max_array
unset($array[$v]); // unset the keys to get next max value
}
}else{ // if not array
$max_array[]=$array[$keys]; // set values to max_array
unset($array[$keys]); // unset the keys to get next max value
}
}
return $max_array;
}
$g = getMaxValue($a,3);
Out Put:
Array
(
[0] => 20
[1] => 15
[2] => 15
[3] => 10
[4] => 10
)
You can modify it to add conditions.
I thought of a couple of other possibilities.
First one:
Find the lowest of the top three values
$min = array_slice(array_unique($a, SORT_NUMERIC), -3)[0];
Filter out any lower values
$top3 = array_filter($a, function($x) use ($min) { return $x >= $min; });
Sort the result
sort($top3);
Advantages: less code
Disadvantages: less inefficient (sorts, iterates the entire array, sorts the result)
Second one:
Sort the array in reverse order
rsort($a);
Iterate the array, appending items to your result array until you've appended three distinct items.
$n = 0;
$prev = null;
$top = [];
foreach ($a as $x) {
if ($x != $prev) $n++;
if ($n > 3) break;
$top[] = $x;
$prev = $x;
}
Advantages: more efficient (sorts only once, iterates only as much as necessary)
Disadvantages: more code
This gives the results in descending order. You can optionally use array_unshift($top, $x) instead of $top[] = $x; to get it in ascending order, but I think I've read that array_unshift is less efficient because it reindexes the array after each addition, so if optimization is important it would probably be better to just use $top[] = $x; and then iterate the result in reverse order.
I'm using a series of MySQL queries to pull back calculations stored by date for graphing via the Flot library. After the calculations are done, the echoed material looks like this (using UNIX timestamp dates):
Item 1:
[
[1159765200000,-117.875],
[1159851600000,-117.25],
[1159938000000,-120.625],
[1160024400000,-122.125],
[1160110800000,-118.125],
[1160370000000,-121.125],
[1160456400000,-123.375],
[1160542800000,-115.625],
[1160629200000,-117.75],
[1160715600000,-112.75],
[1160974800000,-125.25],
[1161061200000,-135],
[1161147600000,-138.375],
[1161234000000,-137],
[1161320400000,-136.25],
[1161579600000,-139.875],
[1161666000000,-146.625],
[1161752400000,-143.625],
[1161838800000,-150.25],
[1161925200000,-152.875],
[1162188000000,-151.75],
[1162274400000,-149.75]
]
Item 2:
[
[1104732000000,47.3913043478],
[1104818400000,45.5072463768],
[1104904800000,45.5797101449],
[1104991200000,45.115942029],
[1105077600000,44.1739130435],
[1105336800000,44.5362318841],
[1105423200000,45.9565217391],
[1105509600000,45.9420289855],
[1105596000000,46.0289855072],
[1105682400000,46.4347826087],
[1106028000000,48.347826087],
[1106114400000,46.8695652174],
[1106200800000,46.4927536232],
[1106287200000,45.6376811594],
[1106546400000,44.3768115942],
[1106632800000,44.0579710145],
[1106719200000,44.5942028986],
[1106805600000,45.0289855072],
[1106892000000,45.231884058],
[1107151200000,46.1449275362],
[1107237600000,46.5942028986],
[1107324000000,45.5652173913],
[1107410400000,45],
[1107496800000,46.2608695652],
[1107756000000,45.7391304348],
[1107842400000,46.3333333333]
]
Basically I'd like to calculate the average of the second value in each pair, controlling for the date. In other words, for each date that matches in each array, print the date and the average of all the second values in each array, e.g:
[Common Date, Average of all second values]
I've looked through a number of array merging techniques but can't seem to find a workable solution.
Thanks very much for any help.
You could construct an array indexed by date in which you put a list of all values for the date:
$byDate = array();
foreach($item1 as $row) {
$date = sprintf('%.0f', $row[0]);
$byDate[$date][] = $row[1];
}
foreach($item2 as $row) {
$date = sprintf('%.0f', $row[0]);
$byDate[$date][] = $row[1];
}
Then you can easily compute the average for each list:
foreach($byDate as $date => $values) {
$avg = array_sum($values) / count($value);
printf("avg for %s: %f\n", $date, $avg);
}
Or compute all averages at once:
function array_avg($array) {
return array_sum($array) / count($array);
}
$avgByDate = array_map('array_avg', $byDate);
Try it here: http://codepad.org/1S1HrYoB
For your merge
$merged_array = array();
function merge_by_time()
{
$passed_arrays = func_get_args();
$merged_array = array();
foreach($passed_arrays as $array)
foreach($array as $value_set){
$merged_array[$value_set[0]][] = $value_set[1];
}
}
return $merged_array;
}
Usage:
$new_array = merge_by_time($array1, $array2, $array3, ...)
Then you'll have an array based on timestamp that has all associated data values contained in it. I think you can take it from here to get the averages?
Second approach
function merge_by_time_and_get_average()
{
$passed_arrays = func_get_args();
$merged_array = array();
foreach($passed_arrays as $array)
foreach($array as $value_set){
$merged_array[$value_set[0]]['data'][] = $value_set[1];
$merged_array[$value_set[0]]['average'] = 0;
foreach($merged_array[$value_set[0]]['data'] as $data_point){
$merged_array[$value_set[0]]['average'] += $data_point;
}
$merged_array[$value_set[0]]['average'] = $merged_array[$value_set[0]]['average']/count($merged_array[$value_set[0]]['data'])
}
}
return $merged_array;
}
Then you have $array[{timestamp}]['data'] containing your data points and $array[{timestamp}]['average'] containing your average of all data points. The nested foreachs are a little messy and expensive, but you can handle it all in one function call.
I am trying to use a function whereby I see how tall (y axis) a two dimensional array is in PHP. How would you suggest that I do this? Sorry, I am new to PHP.
max(array_map('count', $array2d))
If the y-axis is the outer array, then really just count($array). The second dimension would just be count($array[0]) if it's uniform.
A multi-dimensional array is simply an array of arrays -- it's not like you've blocked out a rectangular set of addresses; more like a train where each car can be stacked as high as you like.
As such, the "height" of the array, presumably, is the count of the currently largest array member. #phihag has given a great way to get that (max(array_map(count, $array2d))) but I just want to be sure you understand what it means. The max height of the various arrays within the parent array has no effect on the size or capacity of any given array member.
$max = 0;
foreach($array as $val){
$max = (count($val)>$max?count($val):$max)
}
where $max is the count you are looking for
In my application I have used this approach.
$array = array();
$array[0][0] = "one";
$array[0][1] = "two";
$array[1][0] = "three";
$array[1][1] = "four";
for ($i=0; isset($array[$i][1]); $i++) {
echo $array[$i][1];
}
output: twofour
Probably, this is not the best approach for your application, but for mine it worked perfectly.
To sum up the second dimension, use count in a loop:
$counter = 0;
foreach($var AS $value) {
$counter += count($value);
}
echo $counter;
1.dimension:
count($arr);
2.dimension:
function count2($arr) {
$dim = 0;
foreach ($arr as $v) {
if (count($v) > $dim)
$dim = count($v);
}
return $dim;
}
As it is possible to have each array / vector of different length (unlike a mathematical matrix) you have to look for the max. length.
I've a $max which is essentially a two dimensional array.
Each element in $max is eithor 1 or 0,
can be denoted by $max[$x][$y], where $x is an integer within 0~WIDTH,similar for $y
My purpose is to find rows and columns in the $maxthat sums up greater than a CONSTANT, and get the average distance between rows/columns that qualify.
Anyone has a good solution ?
I have not tested this, but it should work for summing up the columns and rows:
//Map columns and rows into their respective values
//Note that we preserve the col/row indexes
$rowval = array();
$colval = array();
foreach($max as $k1 => $row) {
$rowval[$k1] = array_sum($row);
foreach($row as $k2 => $col) {
if(!isset($colval[$k2])) {
$colval[$k2] = 0;
}
$colval[$k2] += $col;
}
}
//Define filter function
function is_over($val) {
return $val > CONSTANT;
}
//Filter out the cols/rows from their respective arrays
//Keys will be preserved by array_filter
$foundcols = array_filter($colval, 'is_over');
$foundrows = array_filter($rowval, 'is_over');
You still have to calculate the average distance though.