I have a bantracker which logs to MySQL each ban, I would like to get the average difference between each unix time so I can estimate based on the data when the next ban will happen.
My thinking would be Last entry + average? Maybe I am completely wrong and somebody has a better idea.
The Table structure looks like this:
Each apikey is unique.
Any help / ideas are much appreciated I don't mind if it's a MySQL query or PHP code.
Thanks!
You're trying to calculate a moving average:
function moving_average( $array ) {
$z = sizeof( $array );
for ( $i = 1; $i < $z; $i++ ) {
$result[] = $array[ $i ] - $array[ $i-1 ];
}
return array_sum( $result ) / count( $result );
}
Hat tip to: Calculating the average increase from array values in PHP
You can use(COUNT,SUM) to find average
$sql = "SELECT COUNT(time) as count,SUM(time) as sum,MAX(time) as sum FROM table_name";
$avg=$row["sum"]/$row["count"];
Related
I need to get a valid timestamp from the following array:
$arrkeys = array(
"t" => [
1442238840,60,120,180,240,300,360,420,480,540,600,660,720,780,840,900,960,
1442239860,60,120,180,240,300,360,420,480,540,600,660,720,780,840,900,960,
1442240880,60,120,180,240,300,360,420,480,540,600,660,720,780,840,900,960
]
);
I need to sum the first valid timestamp 1442238840 with the following 17 numbers together, to get a correct timestamp, and then, the second timestamp 1442239860, etc...
Example:
1442238840 + 60;
1442238840 + 120;
1442238840 + 180;
etc...
I can't figure out how I could do this,
some things I've tried:
Attempt No. 1
//Pseudo-code
foreach($arrkeys["t"] as $t){
if(strlen($t) < 10){
//Search for the first valid timestamp and sum?
}
}
Attempt No. 2
//Not working.
$array_size = 17;
/* I know that every 17 (counting from 0) have a valid timestamp.
so that 0 = 1st valid timestamp, 20 = 2nd valid timestamp. */
for ($i = 0; $i < $array_size; $i++) {
do {
echo $i;
} while ($i > 0);
I don't know if I'm going the right way to solve this, I don't know how to do this efficiently, or at least do it.
Any suggestions?
I love that you tried different things. That's good!
You tried to solve the problem yourself and array_chunk() will help you a lot here, since you can chunk your array into groups of 17 elements and then use array_sum() to sum each group of 17 elements together, e.g.
$result = array_chunk($arrkeys["t"], 17);
$result = array_map("array_sum", $result);
I have created an array of data, from which I can loop through specific fields and echo these values out, but what I need to do is add these values to a new array, ultimately allowing me to find the average of the values in the new array. As i've said, I can echo out the data, and I think I've figured how to get the average, if only I can create the new array! Any help would be greatly appreciated as I just can't find the answer anywhere, and I'm running low on talent!
My table contains approx 25 fields, im pulling out a number of rows based on a session variable. In the instance im working on, I need to take just the values from 1 column in the table, and add these to an array. The code below will loop through the values, and echo them out, 1 at a time:-
while ($cdarray=mysql_fetch_array($calldata)) {
echo $cdarray['score_total'];
}
This gives me 25555 which are the 4 values I would expect 25, 5, 5, 5
I've tried
while ($cdarray=mysql_fetch_array($calldata)) {
$cdts = $cdarray['score_total'];
$cdtsar = array($cdts);
}
Which results in $cdts being assigned a value of 5,
Any help greatly appreciated!!
This will get your data from the array, place it into a new one and calculates the average.
$cdtsar = array();
while ($cdarray=mysql_fetch_array($calldata)) {
$cdtsar[] = $cdarray['score_total'];
}
$average = array_sum($cdtsar) / count($cdtsar);
It actually prints 25 and 5 and 5 and 5, but there are no spaces in between so it looks like "25555". To verify this yourself:
while ($cdarray=mysql_fetch_array($calldata)) {
echo $cdarray['score_total'];
echo " / ";
}
To get the average, you can either use
$sum = $count = 0;
$average = null;
while ($cdarray=mysql_fetch_array($calldata)) {
$sum += $cdarray['score_total'];
++$count;
}
// Make sure to guard against divide by zero
if ($count) {
$average = $sum / $count;
}
or you might have the database calculate the average for you, if changing the query is an option.
If you want to assign the elements to the new array use like this
$cdtsar = array();
while ($cdarray=mysql_fetch_array($calldata)) {
array_push($cdtsar,$cdarray['score_total']);
}
To find the average of the array
$sum = array_sum($cdtsar);
$num = sizeof($cdtsar);
$avg = $sum/$num;
echo $avg;
I'm fairly new to PHP - programming in general. So basically what I need to accomplish is, create an array of x amount of numbers (created randomly) whose value add up to n:
Let's say, I have to create 4 numbers that add up to 30. I just need the first random dataset. The 4 and 30 here are variables which will be set by the user.
Essentially something like
x = amount of numbers;
n = sum of all x's combined;
// create x random numbers which all add up to n;
$row = array(5, 7, 10, 8) // these add up to 30
Also, no duplicates are allowed and all numbers have to be positive integers.
I need the values within an array. I have been messing around with it sometime, however, my knowledge is fairly limited. Any help will be greatly appreciated.
First off, this is a really cool problem. I'm almost sure that my approach doesn't even distribute the numbers perfectly, but it should be better than some of the other approaches here.
I decided to build the array from the lowest number up (and shuffle them at the end). This allows me to always choose a random range that will allows yield valid results. Since the numbers must always be increasing, I solved for the highest possible number that ensures that a valid solution still exists (ie, if n=4 and max=31, if the first number was picked to be 7, then it wouldn't be possible to pick numbers greater than 7 such that the sum of 4 numbers would be equal to 31).
$n = 4;
$max = 31;
$array = array();
$current_min = 1;
while( $n > 1 ) {
//solve for the highest possible number that would allow for $n many random numbers
$current_max = floor( ($max/$n) - (($n-1)/2) );
if( $current_max < $current_min ) throw new Exception( "Can't use combination" );
$new_rand = rand( $current_min, $current_max ); //get a new rand
$max -= $new_rand; //drop the max
$current_min = $new_rand + 1; //bump up the new min
$n--; //drop the n
$array[] = $new_rand; //add rand to array
}
$array[] = $max; //we know what the last element must be
shuffle( $array );
EDIT: For large values of $n you'll end up with a lot of grouped values towards the end of the array, since there is a good chance you will get a random value near the max value forcing the rest to be very close together. A possible fix is to have a weighted rand, but that's beyond me.
I'm not sure whether I understood you correctly, but try this:
$n = 4;
$max = 30;
$array = array();
do {
$random = mt_rand(0, $max);
if (!in_array($random, $array)) {
$array[] = $random;
$n--;
}
} while (n > 0);
sorry i missed 'no duplicates' too
-so need to tack on a 'deduplicator' ...i put it in the other question
To generate a series of random numbers with a fixed sum:
make a series of random numbers (of largest practical magnitude to hide granularity...)
calculate their sum
multiply each in series by desiredsum/sum
(basicaly to scale a random series to its new size)
Then there is rounding error to adjust for:
recalculate sum and its difference
from desired sum
add the sumdiff to a random element
in series if it doesnt result in a
negative, if it does loop to another
random element until fine.
to be ultratight instead add or
subtract 1 bit to random elements
until sumdiff=0
Some non-randomness resulting from doing it like this is if the magnitude of the source randoms is too small causing granularity in the result.
I dont have php, but here's a shot -
$n = ; //size of array
$targsum = ; //target sum
$ceiling = 0x3fff; //biggish number for rands
$sizedrands = array();
$firstsum=0;
$finsum=0;
//make rands, sum size
for( $count=$n; $count>0; $count--)
{ $arand=rand( 0, $ceiling );
$sizedrands($count)=$arand;
$firstsum+=$arand; }
//resize, sum resize
for( $count=$n; $count>0; $count--)
{ $sizedrands($count)=($sizedrands($count)*$targsum)/$firstsum;
$finsum+=$sizedrands($count);
}
//redistribute parts of rounding error randomly until done
$roundup=$targsum-$finsum;
$rounder=1; if($roundup<0){ $rounder=-1; }
while( $roundup!=0 )
{ $arand=rand( 0, $n );
if( ($rounder+$sizedrands($arand) ) > 0 )
{ $sizedrands($arand)+=$rounder;
$roundup-=$rounder; }
}
Hope this will help you more....
Approch-1
$aRandomarray = array();
for($i=0;$i<100;$i++)
{
$iRandomValue = mt_rand(1000, 999);
if (!in_array($iRandomValue , $aRandomarray)) {
$aRandomarray[$i] = $iRandomValue;
}
}
Approch-2
$aRandomarray = array();
for($i=0;$i<100;$i++)
{
$iRandomValue = mt_rand(100, 999);
$sRandom .= $iRandomValue;
}
array_push($aRandomarray, $sRandom);
I'm learning PHP. Having trouble understanding why this piece of code isn't working.
In particular: why is the result of array_sum($x) (1596) greater than $cap? Perhaps I'm not understanding the nature of while loops, but it seems to me (looking at a print_r($x)), the loop should cut out a step before it actually does.
<?php
function fibonacci_sum($cap = 1000){
list( $cur, $nxt, $seq ) = array( 0, 1, array() );
while ( array_sum($seq) < $cap ) {
$seq[] = $cur;
$add = $cur + $nxt;
$cur = $nxt;
$nxt = $add;
}
return $seq;
}
$x = fibonacci_sum();
echo array_sum($x);
?>
Any insight is appreciated.
Best,
matt
Look at it this way: if array_sum($x) were less than $cap, then the body of the while loop would be executed again. Therefore, when the while loop has stopped executing, by definition the condition at the top of the while will be false. (*) I think you want to say:
while ( array_sum($seq) + $cur < $cap ) {
That will stop just before you exceed $cap, which is what you seem to want to do.
(*) Yeah, yeah, disclaimer about the effect of break statements.
Simple order of execution.
If you add a little variable watcher it's easy to see how this happens
while ( array_sum( $seq ) < $cap )
{
echo $cur, ' : ', array_sum( $seq ), '<br>';
$seq[] = $cur;
$add = $cur + $nxt;
$cur = $nxt;
$nxt = $add;
}
If you run this, the last output shows 610 : 986. So, 986 is less than 1000, which is why that iteration of the loop executes, but the very first line of the loop pushes $cur onto $seq anyway - completely oblivious to the fact that it just made the sum creater than the cap. So when you do array_sum() outside the function, that 610 is part of it, hence the 1596.
So what you really want is when the array sum plus the next value is less than the cap.
while ( array_sum( $seq ) + $cur < $cap )
But, it's a bit weird that your function returns an array at all. Why not just have it return the sum directly?
The sum is less than cap the last time the body of the while loop is entered. That's how while loops work in all major languages. In this case, the sum is greater than cap when the loop is exited for the last time.
If you have an array of ISO dates, how would you calculate the most days between two sequential dates from the array?
$array = array('2009-03-11', '2009-03-12', '2009-04-12', '2009-05-03', '2009-10-30');
I think I need a loop, some sort of iterating variable and a sort. I can't quite figure it out.
This is actually being output from MYSQL.
Here is how you can do it in PHP:
<?php
$array = array('2009-03-11', '2009-03-12', '2009-04-12', '2009-05-03', '2009-10-30');
# PHP was throwing errors until I set this
# it may be unnecessary depending on where you
# are using your code:
date_default_timezone_set("GMT");
$max = 0;
if( count($array) > 1 ){
for($i = 0; $i < count($array) - 1; $i++){
$start = strtotime( $array[$i] );
$end = strtotime( $array[$i + 1] );
$diff = $end - $start;
if($diff > $max) $max = $diff;
}
}
$max = $max / (60*60*24);
?>
It loops throw your items (it executes one less time than there are number of items) and compares each one. If the comparison is larger than the next, it updates max. Time is in seconds, so after the loop is over we convert the seconds into days.
This PHP script will give you the largest interval
1 ){
for($i = 0; $i $maxinterval) $maxinterval = $days;
}
}
?>
EDIT:
As [originally] worded the question can be understood in [at least ;-)] two ways:
A) The array contains a list of dates in ascending order. The task is to find the longuest period (expressed in number of days) between to consecutive dates in the array.
B) The array is not necessarily sorted. The task is to find the longuest period (expr. in number of days) between any two dates in the array
The following provides an answer to the "B" understanding of the question. For a response to "A", see dcneiner's solution
No Sorting needed!...
If it comes from MySQL, you may have this DBMS returns directly the MIN and MAX values for the considered list.
EDIT: As indicated by Darkerstar, the way the way the data is structured [and also the existing SQL query which returns the complete list as indicated in the question] generally dictate the way the query which produces the MIN and MAX value should be structured.
Maybe something like this:
SELECT MIN(the_date_field), MAX(the_date_field)
FROM the_table
WHERE -- whatever where conditions if any
--Note: no GROUP BY needed
If, somehow, you cannot use SQL, a single pass through the list will allow you to obtain the MIN and MAX value in the list (in O(n) time, that is).
Algorithm is trivial:
Set Min and Max Value to first item in [unsorted] list.
Iterate through each following item in the list, comparing it with the Min Value and replacing it if found smaller, and doing like-wise for the Max value...
With Min and Max values in hand, a simple difference gives the max number of days...
In PHP, it's looks like the following:
<?php
$array = array('2009-03-11', '2009-03-12', '2009-04-12', '2009-05-03', '2009-10-30');
# may need this as suggested by dcneiner
date_default_timezone_set("GMT");
$max = $array[0];
$min = $max;
for($i = 1; $i < count($array); $i++){
// Note that since the strings in the array are in the format YYYY-MM-DD,
// they can be compared as-is without requiring say strtotime conversion.
if ($array[$i] < $min)
$min = $array[$i];
if ($array[$i] > $max)
$max = $array[$i];
}
$day_count = (strtotime($max) - strtotime($min)) / (60*60*24);
?>