Possible to pull random entry from array and keep schedule? - php

Not sure if this is possible with just php or if I'd need something else too. Basically I'd like to have an array with a bunch of entries, such as:
(1234,5432,5678,5899,3245)
And I'd like to have the php randomly select one entry from the array AND stick to that entry it selected for 3 days. So for example, on a given date, it would pull "5432" from the array, then it would hold that entry for 3 days, then after 3 days it would pick another entry and hold it for 3 days, etc.
Any ideas how this could be done? Can it be done with just php? Thanks so much for any help.

Assuming you're running a PHP program (command line), and not running a script on a web server you can run this script to stay on all the time and wait to draw.
$entries = array( 34534, 435, 345 );
while(1) {
// subtract 1 from total number of entries because arrays start at an index of 0.
$totalNumberOfEntries = sizeof( $entries ) - 1;
// if no entries left, quit the program
if ($totalNumberOfEntries <= 0) break;
// grab a random index from your array using `mt_rand()` function
$entry = $entries[ mt_rand(0, $totalNumberOfEntries - 1) ];
// write the entry to a file
file_put_contents( 'entry.txt', $entry, FILE_APPEND );
// wait 3 days to draw again
sleep( 3600 * 24 * 3 );
}

Related

Divide single digit into ranges

I can't think a way in PHP to divide number into ranges.
I have massive MySQL database record set and want to spread some workload for my scripts.
Example:
There is 2435 rows in table, I want that each PHP script select only specific range of records:
Script 1: select [1 to 150];
Script 2: select [151 to 270];
The main problem: I can't think a method how to divide that 2435 into even ranges and pass them into MySQL SELECT.
Try Like this way-
SELECT * FROM table_name ORDER BY id ASC LIMIT 150 OFFSET 0
For 1st script,
LIMIT 150 OFFSET 0
then For 2nd script
LIMIT 150 OFFSET 150
So on...
So, for a few days I was testing how offset behaves with massive data sets (100+k rows) and it was terrible. Offset is insanely resource hungry and definitely not for the task if you have large number of rows in your database.
My final code looks like this (abstraction):
chunker.php
// Divide table rows into 50 chunks and produce array
$rows = DB::query("SELECT id FROM data_set GROUP BY id DESC");
$chunks = array_chunk($rows, 50, TRUE);
// Extract endings of each chunk array
$ends = array();
foreach ($chunks as $c) {
$f = flattenArray($c);
$arr_end = end($f);
array_push($ends, $arr_end);
}
// Spawn separate PHP processes to work with a chunk array ending
foreach ($ends as $e) {
$bb = shell_exec("php -q worker.php '".$e."' > /dev/null &");
}
worker.php
// Catch argv
$exec_args = $_SERVER['argv'];
// Select predefined amount of rows from DB which is more than or equal to argv value
$data = DB::query("SELECT * FROM data_set WHERE id >= %i LIMIT 50", $exec_args[1]);
foreach ($data as $d) {
// Do you stuff here
}
This adaptation came from this article http://mysql.rjweb.org/doc.php/pagination
Performance wise I offseting data required 8 CPU cores with 32 GB RAM. With LIMIT method I only need 4 GB RAM and 2 CPU's. So, think twice before using offset in LARGE data sets.

Run script every 2 hours, 6 times in X pattern, 6 times in Y pattern per 24 hours

I want to run a script every two hours, so I use this cron jon command:
0 */2 * * *
The script should use key X when running the first time, and on the following run it should use key Y, and then X again and so on.
My initial idea was to use the server time, and according to whether the hour is odd or even number, it will choose different key:
$h = date('G');
if ( $h & 1 ) {
$key = "X"; } // odd
else {
$key = "Y"; } // even
But since I run it every two hours in the first place, it is bound to use only one of these keys always, so it's not good.
What's a good way to achieve this?
You can write a file "flag.txt" to filesystem, and check if he exists. If it exists, use X and delete file, if it not exists, create file and use Y.
I think that this should work, but I have no tested it. But doing this with date is the easiest to do.
1 to 12 with date
$dDate = date("g");
Lets say that it fires on 0/2/4/6/8/10/12
$iResult = $dDate % 2;
If any of the given fire times is given $iResult will be 0 so in this case
if($iResult != 0) {
//Do X
} else {
//Do Y
}

time difference between two rows - mysql

I wanted to know if there is any way where i can calculate time difference between two rows. I want to calculate time difference for name -> test etc. The name can be in any order.
I want to know if test has two times at row 1 and 3 and then at row 7 and 11, can i calculate time difference between these rows? i.e for row 1 and 3, and other for row 7 and 11.
below image with my database
try using TIMEDIFF() and subquery
SELECT TIMEDIFF((SELECT `entered_at` FROM `demo_test3` WHERE `id`='1'),
(SELECT `entered_at` FROM `demo_test3` WHERE `id`='3'))
If you want to check the difference in PHP you can do something like this.
function secondsBetweenRows($first, $second)
{
return strtotime($second->entered_at) - strtotime($first->entered_at);
}
// group rows by users
$users = []
foreach ($rows as $row) {
$users[$row->name] = $row;
}
// check row difference
$timeDiff = [];
foreach ($users as $userName => $userRows) {
// assume there are always to, if not do some checks here
$timeDiff[$userName] = secondsBetweenRows($userRows[1], $userRows[0]);
}
print_r($timeDiff);
/*
Array
(
[test] => 24
[test1] => 26
)
*/

Pair all elements of an array in all possible combinations php

I've done some searching all i could find is this unfortunately thats not exactly what i'm looking for.
My problem is, i have a list of user ids in an array that could vary in size from 0 to 30+ users.
looks somehting like:
$arr = array(1,2,3);
What i need is to be able to find all pairs possible with this users:
(1 - 2)
(1 - 3)
(2 - 1)
(2 - 3)
(3 - 1)
(3 - 2)
the idea is to be able to create contact lists on a messaging platform so each one has each other on their contact list.
the examples on the question linked above gives me repeating elements and i can't have repeating elements also don't need 3 elements pared together only 2.
You have two objectives from the way I see it:
Display all possible pairs between a and b numbers
Don't display the same combination twice
You can achieve this with two loops and by keeping track of what you've processed already:
$arr = range(1, 30);
$alreadyProcessed = array();
foreach ($arr as $first) {
// Loop the array twice (as #Dagon mentioned)
foreach ($arr as $second) {
// Keep track of what you've already processed
$combination = array($first, $second);
// Sorting the numbers will ensure that 2 - 1 and 1 - 2 are the same
sort($combination);
// Ensure they aren't the same number and you haven't already processed them
if ($first === $second || in_array($combination, $alreadyProcessed)) {
continue;
}
// Output as per your example
echo "($first - $second)" . PHP_EOL;
// Add it to the list of what you've already processed
$alreadyProcessed[] = $combination;
}
}
NOTE: this kind of logic is bad. You're performing an exponential number of repetitions because you're looping an array inside a loop of the same array. This particular example will perform 30 to-the-power-of 30 repetitions (a big, big number of cycles). That's only with 30 entries. What happens if your user base grows to 10,000? Bye bye server.

Identity the available range numbers when two range numbers are overlap

If I have an existing range:
1-10
11-50
Then I will enter a new range from 1 - 60, How could I detect that the new range to be added overlaps to the previous entries? And how can I get the available range? In this case the available range is from 51-60.
Does anyone here have a great idea on this?
Thanks for helping.
Here's my current code:
$saved = array(
array(
"start" => 1,
"end" => 10
),
array(
"start" => 10,
"end" => 50
)
);
$new_range = array(
"start" => 1,
"end" => 60
);
$usable_range = array();
$previous_from = 0;
$previous_to = 0;
foreach($saved as $value)
{
$range_start = 0;
$range_end = 0;
if($previous_from<$value['start'])
{
$previous_from = $value['start'];
}
if($previous_to<$value['end'])
{
$previous_to = $value['end'];
}
if($previous_from<=$new_range['start'])
{
if($previous_to<$new_range['end'])
{
$range_start = $previous_to+1;
$range_end = $new_range['end'];
$new_range['start'] = $range_start;
}
}
else if($previous_from>=$new_range['start'])
{
if($previous_to<$new_range['end'])
{
$range_start = $previous_to+1;
$range_end = $new_range['end'];
$new_range['start'] = $range_start;
}
}
$usable[] = array("range_start"=>$range_start,"range_end"=>$range_end);
}
Call every interval (min,max)
1) Sort your list of intervals by their min.
2) Check to see if any max is greater than the next entry over's min. If they are, create the interval that is the smaller of their mins and the greater of their maxes, and add it back into the list in place of those two.
3) Whenever you get a new interval, binary search into the list to add it, sorted by min. Then, using similar logic as in 2), attempt to merge it with the entry one below and one above until no more merges are possible.
EDIT: A few changes.
First, since we're using integers not floats, if you have an interval like 1,10 and 11,20 then there is no 'gap' between the 10 and 11 - so we should consider this to be one larger interval, 1,20. Reflect this by, instead of checking to see if max > next min, if max >= next min - 1.
Second, if you want to find all intervals formed by overlap when merging a new interval into your list of intervals:
1) Since your list of intervals is known to be in a state where it is sorted by min and also sorted by max, binary search into it to find the lowest min just above your new min and the highest max just above your new max.
2) Iterate over min, max, min, max... etc in your array that are between your new min and new max. Below the lowest min, above the highest max and between each max/min you can compute the interval that is in the 'gap' there, and return them in e.g. an array.
For example if your list of intervals contains 13,16, 21,24 and 31, 38 and you want to calculate the non-overlap of the new interval 1,30:
1) We binary search into our list and find that 13 is the lowest min above 1 and 24 is the highest max above 30.
2) We iterate like so:
Between our min and the lowest min is 1 and 13 - so this forms an interval 1,12 (inclusive bottom, exclusive top). Add onto the return array.
Between max and the next min is 16 and 21 - so this forms an interval 17,20 (exclusive on both ends). Add onto the return array.
Between max and our max is 24 and 30 - so this forms an interval 25,30 (exclusive bottom, inclusive top). Add onto the return array.
Finding overlap can be described as finding an intersection. Likewise finding the available range can be described as finding the difference. One way of doing this would be treating these sets as arrays and using the array_intersect [1] and array_diff [2] functions.
That is all I can come up with given your details.
[1] - http://php.net/manual/en/function.array-intersect.php
[2] - http://www.php.net/manual/en/function.array-diff.php

Categories