Indexing an array every cycle (in seconds) - php

I have to put datas every 10 seconds in an array. Is it silly to index this array with modified timestamps
$a[timestamp] = 54;
$a[timestamp+10] = 34;
or in Javascript with the setInterval() and passing via Ajax the index (very crappy to me) ?
or have I a best option ?
Further details :
I have to link the real-time with entries in my array : this is my problem. At the 3rd cycle (21 sec to 30 sec from the beginning time).
I have only 15 entries to store.
My present code :
$first_time = (int)date('Hi');
$_SESSION['mypile'][$first_time] = array_fill ($first_time, 15, array('paramA' => 0, 'paramB' => 0));
then, the Ajax part calls this script :
$time = (int)date('Hi');
$_SESSION['mypile'][$time]['paramA'] = calcul_temp($_SESSION['mypile'], $time);

Why would you not use a plain numerically indexed array? If you don't need the timestamp, then:
$a[] = 54;
$a[] = 34;
If you do need the timestamp, then it would make more sense to do something like:
$a[] = array('timestamp' => time(), 'number' => 54);
$a[] = array('timestamp' => time(), 'number' => 34);
Then at each offset you have a more meaningful associative array:
echo 'Timestamp: ' . $a[0]['timestamp'] . ', Number: ' . $a[0]['number'];
If those operations happen in rapid succession, you would probably be better using microtime

That seems like a very good solution, though you will have to be careful about memory usage if the script will be running for a long time.

That is fairly silly; if you've set a time interval, simply have your function be called every 10 seconds and add your new number to the next index in the array. Keep track of this index globally or within the scope of the iteration.

$a['timestamp'] = time();
while (true) {
$a['data'][] = getData();
sleep(10);
}
You could make a class of it. The construct then sets the timestamp, and with SPL array index and iterator it can be looped in foreach and used with some array functions. You can make a method to get an array with or without the timestamp, etc.
$dataCycle = new DataCycle();
while(true) {
$dataCycle->addData(getData());
sleep(10);
}

Ok so I decided to round my timestamp every 10 seconds to have pieces of time. Simple, silly and work for me.
Thank you for ideas.

Related

PHP Find Gaps over the course of N years across multiple date ranges

Taking a multidimensional array such as
array(
array('begin' => '2006-01-01', 'finish' => '2006-02-28'),
array('begin' => '2006-03-01', 'finish' => '2006-06-30'),
array('begin' => '2006-08-01', 'finish' => '2007-12-30'),
array('begin' => '2007-01-01', 'finish' => '2016-12-30'),
);
I am trying to figure out the best way to process Nth number of arrays with varying degrees of ranges and overlaps to see if there is an gaps over the course of N years. My current requirement is down to the month. But I simply can not currently wrap my head around this. Without going through a series of nested foreaches that ultimately paint me in a corner and are way to expensive to process on bigger data sets.
This code is hopefully in O(n) and assumes that it's an ordered array as in the example.
I used that this date format can be compared as strings and gives the same result, as if you'd worked with complex date objects.
// $a is your multidimensional array as above
$gap = array();
for($i=1; $i<sizeof($a); $i++){
$gap[$i] = $a[$i-1]['finish'] < $a[$i]['begin'];
}
$gap contains an array or booleans, which indicate at which indexes there is a gap.
I'm not going to suggest an actual implementation, but more a general approach.
You can usually look at this kind of problems two ways:
Make super smart code. Craft an algorithm that recursively merges the ranges that overlaps, leaving you with an array of discrete ranges. You have gaps if you have more than one row in the array, and the gaps are defined between the end of a range and the start of another one. The keyword here is recursively.
Make super dumb code. Build an assoc array with all the months of your interval (that can't be very much, even 10 years is only 120 months) as keys, and "true" as value. Iterate your array, and set the months that appears in a range to "false". Use array_filter and ta-dah! You're left with the months having gaps. The key here is to not use date related functions (they're slow) and instead just go at it arithmetically.
Hope this help putting you on the right track.
Not widely tested and needs some refactoring, but this is the best algorithm I could come up with (I've done something similar with database actually):
define('DAY_SEC', 86400);
$result = [];
foreach ($dates as $date) {
$begin = strtotime($date['begin']);
$finish = strtotime($date['finish']);
$merged = null;
foreach ($result as $idx => $span) {
if ($span['begin'] <= $finish + DAY_SEC && $span['finish'] >= $begin - DAY_SEC) {
if (isset($merged)) {
$min = min($span['begin'], $begin, $result[$merged]['begin']);
$max = max($span['finish'], $finish, $result[$merged]['finish']);
unset($result[$idx]);
} else {
$min = min($span['begin'], $begin);
$max = max($span['finish'], $finish);
$merged = $idx;
}
$result[$merged] = ['begin' => $min, 'finish' => $max];
}
}
if (!isset($merged)) {
$result[] = ['begin' => $begin, 'finish' => $finish];
}
}
foreach ($result as &$span) {
$span['begin'] = date('Y-m-d', $span['begin']);
$span['finish'] = date('Y-m-d', $span['finish']);
}
It will result in array of continuous timespans. It adds timespans one by one and merges them when overlaping with all previously added. If it overlaps more than one period then it merges consecutive matches into the first one.

How to get the length of a (by reference) array

I am looping through several thousands of rows from a mysql result and adding them to different arrays.
I get a reference to the last element in the array to operate on (for reasons outside the scope of this question).
I.e. (just an example of the scenario)
$myarray = array();
$result = &$myarray;
$row = &$result[count($result)-1]
Of course this works, but as this thread ( Why is calling a function (such as strlen, count etc) on a referenced value so slow? ) explains , calling a function which doesnt expect a variable by reference , With a variable by reference, causes the function to make a copy of the variable to operate on.
As my $result array grows to thousands of elements , continuously calling count on it , causing copies of it being made , makes the code unusable slow.
How can I get around this - Without suggesting to not use variables by reference.
Also, I cant keep separate rowcounters.
Basically I need to know how to dereference a by-reference variable (which I understand cant be done) , or some other way to get a array length ? , or a way to get a reference to the last row in an array (without popping it)
Bearing in mind the array could also be empty.
Already took me ages to find out that This is the problem , so I would really appreciate any help with solving the problem.
EDIT
To everyone that says that count cannot possibly be slower than end/key:
Just run this simple test to confirm
//setup array of 10 000 elements
$ar = array();
for ($i = 0 ; $i < 10000 ; $i++)
{
$ar[] = $i;
}
//get a reference to it
$ref = &$ar;
error_log (date("Y/m/d H:i:s")." : speed test 1 \r\n",3,"debug.log");
//do 10 000 counts on the referenced array
for ($i = 0 ; $i < 10000 ; $i++)
{
$size = count($ref);
}
error_log (date("Y/m/d H:i:s")." : speed test 2 \r\n",3,"debug.log");
//do 10 000 end/key on the referenced array
for ($i = 0 ; $i < 10000 ; $i++)
{
reset($ref);
end($ref);
$size = key($ref);
}
error_log (date("Y/m/d H:i:s")." : end \r\n",3,"debug.log");
Output: 15 seconds to do the counts ... less than a second to do the end/key
2012/07/10 17:25:38 : speed test 1
2012/07/10 17:25:53 : speed test 2
2012/07/10 17:25:53 : end
I'm still not sure I understand why this is necessary. However, you've indexed the array as a numerical sequential array, so you can do this "trick" to get the size:
// Make sure the array pointer is at the end of the array
end($result); // Not sure if this is necessary based on your description
$size = key($result) + 1; // Get the numeric key of the last array element
Note that both end() and key() take their parameters by reference. However, I wouldn't be surprised if they're now operating on references of references, but this is something you can investigate.
depending on your other needs, that you mentioned but didn't descripe, maybe a few of the realy oldschool (deep level) functions coud help:
end($result); // set pointer to (current) last element
$pos = key($result); //index of the last element
$row = &$result($pos);
edit: I type too slow :)
You should have a look to the SPL data structures. Maybe a simple SplHeap or SplDoublyLinkedList can fit to your requirements. Moreover, performances are pretty good!

Picking the nearest value from an array reflecting ranges

I have an array that reflects rebate percentages depending on the number of items ordered:
$rebates = array(
1 => 0,
3 => 10,
5 => 25,
10 => 35)
meaning that for one or two items, you get no rebate; for 3+ items you get 10%, for 5+ items 20%, for 10+ 35% and so on.
Is there an elegant, one-line way to get the correct rebate percentage for an arbitrary number of items, say 7?
Obviously, this can be solved using a simple loop: That's not what I'm looking for. I'm interested whether there is a core array or other function that I don't know of that can do this more elegantly.
I'm going to award the accepted answer a bounty of 200, but apparently, I have to wait 24 hours until I can do that. The question is solved.
Here's another one, again not short at all.
$percent = $rebates[max(array_intersect(array_keys($rebates),range(0,$items)))];
The idea is basically to get the highest key (max) which is somewhere between 0 and $items.
I think that the above one-line solutions aren't really elegant or readable. So why not use something that can really be understood by someone on first glance?
$items = NUM_OF_ITEMS;
$rabate = 0;
foreach ($rabates as $rItems => $rRabate) {
if ($rItems > $items) break;
$rabate = $rRabate;
}
This obviously needs a sorted array, but at least in your example this is given ;)
Okay, I know, you don't want the solution with the simple loop. But what about this:
while (!isset($rabates[$items])) {
--$items;
}
$rabate = $rabates[$items];
Still quite straightforward, but a little shorter. Can we do even shorter?
for (; !isset($rabates[$items]); --$items);
$rabate = $rabates[$items];
We are already getting near one line. So let's do a little bit of cheating:
for (; !isset($rabates[$items]) || 0 > $rabate = $rabates[$items]; --$items);
This is shorter then all of the approaches in other answers. It has only one disadvantage: It changes the value of $items which you may still need later on. So we could do:
for ($i = $items; !isset($rabates[$i]) || 0 > $rabate = $rabates[$i]; --$i);
That's again one character less and we keep $items.
Though I think that the last two versions are already too hacky. Better stick with this one, as it is both short and understandable:
for ($i = $items; !isset($rabates[$i]); --$i);
$rabate = $rabates[$i];
This might work without changing the rebate array.
But the array must be constructed in another way for this to work
$rebates = array(
3 => 0, //Every number below this will get this rebate
5 => 10,
10 => 25,
1000 => 35); //Arbitrary large numer to catch all
$count = $_REQUEST["count"];
$rv = $rebates[array_shift(array_filter(array_keys($rebates), function ($v) {global $count; return $v > $count;}))];
echo $rv;
Working testcase, just change count in url
http://empirium.dnet.nu/arraytest.php?count=5
http://empirium.dnet.nu/arraytest.php?count=10
Best I can manage so far:
$testValue = 7;
array_walk( $rebates, function($value, $key, &$test) { if ($key > $test[0]) unset($test[1][$key]); } array($testValue,&$rebates) );
Uses a nasty little quirk of passing by reference, and strips off any entry in the $rebates array where the key is numerically greater than $testValue... unfortunately, it still leaves lower-keyed entries, so an array_pop() would be needed to get the correct value. Note that it actively reduces the entries in the original $rebates array.
Perhaps somebody can build on this to discard the lower entries in the array.
Don't have 5.3.3 available to hand at the moment, so not tested using an anonymous function, but works (as much as it works) when using a standard callback function.
EDIT
Building on my previous one-liner, adding a second line (so probably shouldn't count):
$testValue = 7;
array_walk( $rebates, function($value, $key, &$test) { if ($key > $test[0]) unset($test[1][$key]); } array($testValue,&$rebates) );
array_walk( array_reverse($rebates,true), function($value, $key, &$test) { if ($key < $test[0]) unset($test[1][$key]); } array(array_pop(array_keys($rebates)),&$rebates) );
Now results in the $rebates array containing only a single element, being the highest break point key from the original $rebates array that is a lower key than $testValue.

Get single column from 2d array [duplicate]

This question already has answers here:
Is there a function to extract a 'column' from an array in PHP?
(15 answers)
Closed 4 months ago.
This is my array
Array
(
[0] => Array
(
[sample_id] => 3
[time] => 2010-05-30 21:11:47
)
[1] => Array
(
[sample_id] => 2
[time] => 2010-05-30 21:11:47
)
[2] => Array
(
[sample_id] => 1
[time] => 2010-05-30 21:11:47
)
)
And I want to get all the sample_ids in one array. can someone please help ?
Can this be done without for loops (because arrays are very large).
$ids = array_map(function($el){return $el["sample_id"];}, $array);
Or in earlier versions:
function get_sample_id($el){return $el["sample_id"];}
$ids = array_map('get_sample_id', $array);
However, this is probably not going to be faster.
This is a problem I've had MANY times. There isn't an easy way to flatten arrays in PHP. You'll have to loop them adding them to another array. Failing that rethink how you're working with the data to use the original structure and not require the flatten.
EDIT: I thought I'd add a bit of metric information, I created an array $data = array(array('key' => value, 'value' => other_value), ...); where there were 150,000 elements in my array. I than ran the 3 typical ways of flattening
$start = microtime();
$values = array_map(function($ele){return $ele['key'];}, $data);
$end = microtime();
Produced a run time of: Run Time: 0.304405 Running 5 times averaged the time to just below 0.30
$start = microtime();
$values = array();
foreach ($data as $value) {
$values[] = $value['key'];
}
$end = microtime();
Produced a run time of Run Time: 0.167301 with an average of 0.165
$start = microtime();
$values = array();
for ($i = 0; $i < count($data); $i++) {
$values[] = $data[$i]['key'];
}
$end = microtime();
Produced a run time of Run Time: 0.353524 with an average of 0.355
In every case using a foreach on the data array was significantly faster. This is likely related to the overhead of the execution of a function for each element in the array for hte array_map() implementation.
Further Edit: I ran this testing with a predefined function. Below are the average numbers over 10 iterations for 'On the Fly' (defined inline) and 'Pre Defined' (string lookup).
Averages:
On the fly: 0.29714539051056
Pre Defined: 0.31916437149048
no array manitulation can be done without a loop.
if you can't see a loop, it doesn't mean it's absent.
I can make a function
array_summ($array) {
$ret=0;
foreach ($array as $value) $ret += $value;
return $ret;
}
and then call it array_summ($arr) without any visible loops. But don't be fooled by this. There is loop. Every php array function iterate array as well. You just don't see it.
So, the real solution you have to look for, is not the magic function but reducing these arrays.
From where it came? From database most likely.
Consider to make a database to do all the calculations.
It will save you much more time than any PHP bulit in function
I don't think you'll have any luck doing this without loops. If you really don't want to iterate the whole structure, I'd consider looking for a way to alter your circumstances...
Can you generate the sample_id data structure at the same time the larger array is created?
Do you really need an array of sample_id entries, or is that just a means to an end? Maybe there's a way to wrap the data in a class that uses a cache and a cursor to keep from iterating the whole thing when you only need certain pieces?

Which is faster in PHP, $array[] = $value or array_push($array, $value)?

What's better to use in PHP for appending an array member,
$array[] = $value;
or
array_push($array, $value);
?
Though the manual says you're better off to avoid a function call, I've also read $array[] is much slower than array_push(). What are some clarifications or benchmarks?
I personally feel like $array[] is cleaner to look at, and honestly splitting hairs over milliseconds is pretty irrelevant unless you plan on appending hundreds of thousands of strings to your array.
I ran this code:
$t = microtime(true);
$array = array();
for($i = 0; $i < 10000; $i++) {
$array[] = $i;
}
print microtime(true) - $t;
print '<br>';
$t = microtime(true);
$array = array();
for($i = 0; $i < 10000; $i++) {
array_push($array, $i);
}
print microtime(true) - $t;
The first method using $array[] is almost 50% faster than the second one.
Some benchmark results:
Run 1
0.0054171085357666 // array_push
0.0028800964355469 // array[]
Run 2
0.0054559707641602 // array_push
0.002892017364502 // array[]
Run 3
0.0055501461029053 // array_push
0.0028610229492188 // array[]
This shouldn't be surprising, as the PHP manual notes this:
If you use array_push() to add one element to the array it's better to use $array[] = because in that way there is no overhead of calling a function.
The way it is phrased I wouldn't be surprised if array_push is more efficient when adding multiple values. Out of curiosity, I did some further testing, and even for a large amount of additions, individual $array[] calls are faster than one big array_push. Interesting.
The main use of array_push() is that you can push multiple values onto the end of the array.
It says in the documentation:
If you use array_push() to add one
element to the array it's better to
use $array[] = because in that way
there is no overhead of calling a
function.
From the PHP documentation for array_push:
Note: If you use array_push() to add one element to the array it's better to use $array[] = because in that way there is no overhead of calling a function.
Word on the street is that [] is faster because no overhead for the function call. Plus, no one really likes PHP's array functions...
"Is it...haystack, needle....or is it needle haystack...ah, f*** it...[] = "
One difference is that you can call array_push() with more than two parameters, i.e. you can push more than one element at a time to an array.
$myArray = array();
array_push($myArray, 1,2,3,4);
echo join(',', $myArray);
prints 1,2,3,4
A simple $myarray[] declaration will be quicker as you are just pushing an item onto the stack of items due to the lack of overhead that a function would bring.
Since "array_push" is a function and it called multiple times when it is inside the loop, it will allocate memory into the stack.
But when we are using $array[] = $value then we are just assigning a value to the array.
Second one is a function call so generally it should be slower than using core array-access features. But I think even one database query within your script will outweight 1000000 calls to array_push().
See here for a quick benchmark using 1000000 inserts: https://3v4l.org/sekeV
I just wan't to add : int array_push(...) returns
the new number of elements in the array (PHP documentation). which can be useful and more compact than $myArray[] = ...; $total = count($myArray);.
Also array_push(...) is meaningful when variable is used as a stack.

Categories