So I have a multidimensional array, containing 36 arrays.
I want for a page to display an "Item of the day" in the way that each array is only available for a specific date, and then not again until all the other array have been featured on other days first. The collection doesn't necessarily need to be randomized.
This is not a duplicate of this because in my case I cannot edit or even do direct queries on any database, nor can I write to files or anything else to permanently mark that an item has been featured.
I can however store perhaps a variable containing the initiation date, which could be used as a reference point to somehow calculate which array should be displayed on the current date.
However, math was never my strong suite so I don't know how to do such very very complex calculations. Nor do I have the programming heft to know if this concept is even the best one.
What do you suggest?
I'm not sure if this counts, but you could do modulo operation on the current date:
$messages = array('hi, how are you', 'nice weather eh?', 'get lost!');
$idx = floor(time() / 86400) % count($messages);
echo $messages[$idx];
Every day it will pick one for that whole day; then move to the next, etc. At the end it goes back to the beginning.
It's sort of random what the first item will be, but after that it's sequential.
I'd reckon you'd have to store the data outside of the program/page code, in order to check against it (dates, etc) each time/each day you load the page.
Related
thanks for taking the time to look at my question. I'm working on something that's dynamic and has data added daily, but is sorted from first to last in the JSON file, when I want to go from last (most recent) to first.
What I did was get the total number of entries by simply using
$total = $response['result']['total'];
Which gives me the total, 84. If I want the next last in the sequence, I just go:
echo $total - 1
Which gives me 83.
This is where the problem comes in
I'm arranging my data like this:
echo $reo[0]['previous_day_doses_administered'];
Where the [0] is, I want $total - 1
However, I'm not sure how to get it, as it would be
$reo[$response['result']['total']]['previous_day_doses_administered'];
which is definitely wrong. I'm wondering how to convert the $total to an integer, and have it no longer associated with the JSON array. I'm sorry if this is confusing! I just want to have the last 10 entries show up, instead of the first 10.
So, that's basically it. I've tried a couple things I found on here, but it screwed everything up. The API updates daily. If you want the link, let me know.
Thanks for taking the time to read this, and sorry that I'm being so confusing!
I have a model Task(id, start_date, end_date, description). I use Paginator like
$this->Paginator->settings = array(
'Task'=>array(
'contain'=>$contain,
'limit'=> $limit,
'conditions'=>$conditions,
'order'=>'Task.start_date ASC',
'page'=> $page,
));
What I'm after is to be able to know the range of start_date covered by each page of the paged set. Instead of page numbers (i.e. in view generated by $this->Paginator->numbers()) I'd like to create links like "2 weeks ago" and "Today" that jump to the page containing the first Task with start_date > NOW()-14Days, for example.
I fully understand I could alter my $conditions and set a range on the start_date, but I want the whole set.
Open to other ideas on how to achieve the same result, or any pointers in the right direction.
You need to calculate the records before and after the given start date of your condition and then divide it by the number of records per page to get the page it is on.
However, this is not very user friendly, instead I would do this:
Pass your start date and range in the URL and based on the passed values build your query that you then use within your pagination settings.
/something/index?range=last-two-weeks
And check for the range value and do a switch for that value to set the right conditions. This will directly filter only the records the user is really interested in by a clear to understand URL.
I ended up running my search twice, once paginated, once not. I then went through the unpaged results
$pgStarts = array();
$pgCounter = 1;
foreach($tasks as $k => $task){
if(($k % $limit) == 0){
$pgStarts[$pgCounter] = $task['Task']['start_time'];
$pgCounter++;
}
}
Once I had the array of start dates for each page I could easily change the way the paging numbers were labeled. I was even able to break down the key event day by hour (most tasks are on this day).
I'm happy with the result, as I think it gives the paging more context. I'll continue to look for a better way of doing it, but this will do for now.
So recently I was given a problem, which I have been mulling over and am still unable to solve; I was wondering if anyone here could point me in the right direction by providing me with the psuedo code (or at least a rough outline of the pseudo code) for this problem. PS I'll be building in PHP if that makes a difference...
Specs
There are ~50 people (for this example I'll just call them a,b,c... ) and the user is going to group them into groups of three (people in the groups may overlap), and in the end there will be 50-100 groups (ie {a,b,c}; {d,e,f}; {a,d,f}; {b,c,l}...). *
So far it is easy, it is a matter of building an html form and processing it into a multidimensional array
There are ~15 time slots during the day (eg 9:00AM, 9:20AM, 9:40AM...). Each of these groups needs to meet once during the day. And during one time slot the person cannot be double booked (ie 'a' cannot be in 2 different groups at 9:40AM).
It gets tricky here, but not impossible, my best guess at how to do this would be to brute force it (pick out sets of groups that have no overlap (eg {a,b,c}; {l,f,g}; {q,n,d}...) and then just put each into a time slot
Finally, the schedule which I output needs to be 'optimized', by that I mean that 'a' should have minimal time between meetings (so if his first meeting is at 9:20AM, his second meeting shouldn't be at 2:00PM).
Here's where I am lost, my only guess would be to build many, many schedules and then rank them based on the average waiting time a person has from one meeting to the next
However My 'solutions' (I hesitate to call them that) require too much brute force and would take too long to create. Are there simpler, more elegant solutions?
These are the table laid out, modified for your scenerio
+----User_Details------+ //You may or may not need this
| UID | Particulars... |
+----------------------+
+----User_Timeslots---------+ //Time slots per collumn
| UID | SlotNumber(bool)... | //true/false if the user is avaliable
+---------------------------+ //SlotNumber is replaced by s1, s2, etc
+----User_Arrangements--------+ //Time slots per collumn
| UID | SlotNumber(string)... | //Group session string
+-----------------------------+
Note: That the string in the Arrangement table, was in the following format : JSON
'[12,15,32]' //From SMALLEST to BIGGEST!
So what happens in the arrangement table, was that a script [Or an EXCEL column formula] would go through each slot per session, and randomly create a possible session. Checking all previous sessions for conflicts.
/**
* Randomise a session, in which data is not yet set
**/
function randomizeSession( sesionID ) {
for( var id = [lowest UID], id < [highest UID], id++ ) {
if( id exists ) {
randomizeSingleSession( id, sessionID );
} //else skips
}
}
/**
* Randomizes a single user in a session, without conflicts in previous sessions
**/
function randomizeSingleSession( id, sessionID ) {
convert sessionID to its collumns name =)
get the collumns name of all ther previous session
if( there is data, false, or JSON ) {
Does nothing (Already has data)
}
if( ID is avaliable in time slot table (for this session) ) {
Get all IDs who are avaliable, and contains no data this session
Get all the UID previous session
while( first time || not yet resolved ) {
Randomly chose 2
if( there was conflict in UID previous session ) {
try again (while) : not yet resolved
} else {
resolved
}
}
Registers all 3 users as a group in the session
} else {
Set session result to false (no attendance)
}
}
You will realize the main part of the assignment of groups is via randomization. However, as the amount of sessions increases. There will be more and more data to check against for conflicts. Resulting to a much slower performance. However large being, ridiculously large, to an almost perfect permutation/combination formulation.
EDIT:
This setup will also help ensure, that as long as the user is available, they will be in a group. Though you may have pockets of users, having no user group (a small number). These are usually remedied by recalculating (for small session numbers). Or just manually group them together, even if it is a repeat. (having a few here and there does not hurt). Or alternatively in your case, along with the remainders, join several groups of 3's to form groups of 4. =)
And if this can work for EXCEL with about 100+ ppl, and about 10 sessions. I do not see how this would not work in SQL + PHP. Just that the calculations may actually take some considerable time both ways.
Okay, for those who just join in on this post, please read through all the comments to the question before considering the contents of this answer, as this will very likely fly over your head.
Here is some pseudo code in PHP'ish style:
/* Array with profs (this is one dimensional here for the show, but I assume
it will be multi-dimensional, filled with availability and what not;
For the sake of this example, let me say that the multi-dimensional array
contains the following keys: [id]{[avail_from],[avail_to],[last_ses],[name]}*/
$profs = array_fill(0, $prof_num, "assoc_ids");
// Array with time slots, let's say UNIX stamps of begin time
$times = array_fill(0, $slot_num, "time");
// First, we need to loop through all the time slots
foreach ($times as $slot) {
// See when session ends
$slot_end = $slot + $session_time;
// Now, run through the profs to see who's available
$avail_profs = array(); // Empty
foreach ($profs as $prof_id => $data) {
if (($data['avail_from'] >= $slot) && ($data['avail_to'] >= $slot_end)) {
$avail_prof[$prof_id] = $data['last_ses'];
}
}
/* Reverse sort the array so that the highest numbers (profs who have been
waiting the longest) will be up top */
arsort($avail_profs);
$profs_session = array_slice($avail_profs, 0, 3);
$profs_session_names = array(); // Empty
// Reset the last_ses counters on those profs
foreach ($profs_session as $prof_id => $last_ses) {
$profs[$prof_id]['last_ses'] = 0;
$profs_session_names[0] = $profs[$prof_id]['name'];
}
// Now, loop through all profs to add one to their waiting time
foreach ($profs as $prof_id = > $data) {
$profs[$prof_id]['last_ses']++;
}
print(sprintf('The %s session will be held by: %s, $s, and %s<br />', $slot,
$profs_session_names[0], $profs_session_names[1],
$profs_session_names[2]);
unset ($profs_session, $profs_session_names, $avail_prof);
}
That should print something like:
The 9:40am session will be held by: C. Hicks, A. Hole, and B.E.N. Dover
I see an object model consisting of:
Panelists: a fixed repository of of your the panelists (Tom, Dick, Harry, etc)
Panel: consists of X Panelists (X=3 in your case)
Timeslots: a fixed repository of your time slots. Assuming fixed duration and only occurring on a single day, then all you need is track is start time.
Meeting: consists of a Panel and Timeslot
Schedule: consists of many Meetings
Now, as you have observed, the optimization is the key. To me the question is: "Optimized with respect to what criteria?". Optimal for Tom might means that the Panels on which he is a member lay out without big gaps. But Harry's Panels may be all over the board. So, perhaps for a given Schedule, we compute something like totalMemberDeadTime (= sum of all dead time member gaps in the Schedule). An optimal Schedule is the one that is minimal with respect to this sum
If we are interested in computing a technically optimal schedule among the universe of all schedules, I don't really see an alternative to brute force .
Perhaps that universe of Schedules does not need to be as big as might first appear. It sounds like the panels are constituted first and then the issue is to assign them to Meetings which them constitute a schedule. So, we removed the variability in the panel composition; the full scope of variability is in the Meetings and the Schedule. Still, sure seems like a lot of variability there.
But perhaps optimal with respect to all possible Schedules is more than we really need.
Might we define a Schedule as acceptable if no panelist has total dead time more than X? Or failing that, if no more than X panelists have dead time more than X (can't satisfy everyone, but keep the screwing down to a minimum)? Then the user could assign meeting for panels containing the the more "important" panelists first, and less-important guys simply have to take what they get. Then all we have to do is fine a single acceptable Schedule
Might it be sufficient for your purposes to compare any two Schedules? Combined with an interface (I'm seeing a drag-and-drop interface, but that's clearly beyond the point) that allows the user to constitute a schedule, clone it into a second schedule, and tweak the second one, looking to reduce aggregate dead time until we can find one that is acceptable.
Anyway, not a complete answer. Just thinking out loud. Hope it helps.
In php - how do I display 5 results from possible 50 randomly but ensure all results are displayed equal amount.
For example table has 50 entries.
I wish to show 5 of these randomly with every page load but also need to ensure all results are displayed rotationally an equal number of times.
I've spent hours googling for this but can't work it out - would very much like your help please.
please scroll down for "biased randomness" if you dont want to read.
In mysql you can just use SeleCT * From table order by rand() limit 5.
What you want just does not work. Its logically contradicting.
You have to understand that complete randomness by definition means equal distribution after an infinite period of time.
The longer the interval of selection the more evenly the distribution.
If you MUST have even distribution of selection for example every 24h interval, you cannot use a random algorithm. It is by definition contradicting.
It really depends no what your goal is.
You could for example take some element by random and then lower the possibity for the same element to be re-chosen at the next run. This way you can do a heuristic that gives you a more evenly distribution after a shorter amount of time. But its not random. Well certain parts are.
You could also randomly select from your database, mark the elements as selected, and now select only from those not yet selected. When no element is left, reset all.
Very trivial but might do your job.
You can also do something like that with timestamps to make the distribution a bit more elegant.
This could probably look like ORDER BY RAND()*((timestamps-min(timestamps))/(max(timetamps)-min(timestamps))) DESC or something like that. Basically you could normalize the timestamp of selection of an entry using the time interval window so it gets something between 0 and 1 and then multiply it by rand.. then you have 50% fresh stuff less likely selected and 50% randomness... i am not sure about the formular above, just typed it down. probably wrong but the principle works.
I think what you want is generally referred to as "biased randomness". there are a lot of papers on that and some articles on SO. for example here:
Biased random in SQL?
Copy the 50 results to some temporary place (file, database, whatever you use). Then everytime you need random values, select 5 random values from the 50 and delete them from your temporary data set.
Once your temporary data set is empty, create a new one copying the original again.
I need help with an algorithm to allocate rooms to people. I need to shuffle through a list of rooms to assign a room to a person and after the fourth person is assigned to the room, it should be out of the list(should be unavailable). I have not had any luck with PHP shuffling and sorting functions yet.
Any help (pointers, references, etc.) will greatly be appreciated.
This sounds like both a homework assignment and a problem with thousands of solutions.
As Jack already said, try to develop your algorithm before you try to implement it in code. If you're having trouble understanding this, then just imagine the scenario and try to write simple rules for solving it in real life
Let's say I have a hallway with 10 rooms. Each room can support up to 4 people. Then 35 people show up and want to be assigned to rooms. How would I do this?
I would probably start at the beginning of the hallway and fill up the first room, then fill up the next room, and continue until I ran out of people or rooms (whichever came first). This solution has the advantage of not having to walk very far down the hallway, but the disadvantage of crowding 4 people into one room instead of spreading them evenly.
If you chose to spread them evenly then you'd want to put one in the first room, then one in the second room, etc. Do this until you run out of rooms, then go back through every room putting a second person.
Since you have two methods of doing this, the next step is determining how to represent your basic components in code. You need a way to represent a room and a way to represent a person. The most important feature of a room is that it can hold up to four people, but it always has to know how many people it's holding. Therefore it might be good to think of each room as it's own number, the number telling you how many people are already in that room.
In PHP, if you want several numbers which are related and ordered (as the rooms in a hallway would be) you use an array. This is true when you have several of ANY variable that need to be related to one another and maintain their respective order.
$rooms = array(0, 0, 0, 0, 0); // 5 rooms, all with 0 people in them
If your room needs to know who is staying in the room (if they need to differentiate between different guests) then you might consider each individual room as a 4-element array, each element of which represents a person and is able to identify that person.
$rooms = array(
array(null, null, null, null),
array(null, null, null, null),
array(null, null, null, null),
array(null, null, null, null),
array(null, null, null, null)
);
After you've created your rooms, you have a certain number of people who are waiting to enter a room. Since each person only counts as 1, unless you need to remember extra information about each person (such as their name, age, etc.) then you should be able to see a very convenient way of representing people.
$peopleNotInARoomYet = 10;
If you do need to remember extra information about these people (suppose after assigning rooms you are asked the question "In which room is Bob?") then you would need something much more intelligent. Perhaps an array of classes, each class representing a person. Unless, of course, the person need only be represented by a single variable. Then you could boil them doing to just an array.
$peopleNotInARoomYet = array("Bob", "Sally", "Bill", "Mary");
//or
$peopleNotInARoomYet = array(new Person('Bob'), new Person('Sally'), new Person('Bill'), new Person('Mary'));
Note that the second method required the Person class already be defined, and it can get very convoluted if you aren't careful.
Once you have a way of representing the people, you want to loop through every person to find them a room. If people are represented by a single number, this would look like:
while($peopleNotInARoomYet > 0){
// Assign a room
$peopleNotInARoomYet--;
}
If the people are represented as an array, you might want to consider the PHP array_pop() function.
PHP.net array_pop manual
$nextPerson = array_pop($peopleNotInARoomYet){
while($nextPerson != NULL){
// Assign a room
$nextPerson = array_pop($peopleNotInARoomYet);
}
Having a way to represent rooms and people now, your new task is to take our definition of assignment from above and turn it into code. So let's look at our first (and probably simpler) method. We put people into a room until it's full, then go to the next room.
This actually poses a few algorithmic challenges. First, how do you "put someone into a room"?
The answer to this actually depends on which definition of a room we used. If we simply had an array of integers (the case when we care how many people are in a room but do not care who is in the room) then we need to add one to this integer.
If we had an array of 4-element arrays, then we need to find the first empty element and place the person in that element. Putting a person into a non-empty element will replace the person who was there before.
Since it's obvious from this first attempt to convert our rule set to code that the method will differ depending on the implementation chosen, for the rest of the example I will assume that rooms need only know how many people are in them, and not who is in them in specific. If you do need this further information, that's a lesson left up to the reader to figure out on their own.
So here's our definition of a room, a person, and the beginning of our loop:
<?php
$rooms = array(0, 0, 0, 0, 0); // 5 empty rooms
$peopleNotInRoomsYet = 14; // We'll choose a number that won't divide evenly
while($peopleNotInRoomsYet > 0){
// Assign a room
$peopleNotInRoomsYet --;
}
?>
And we know that once we've chosen which room to put someone in, actually putting them there involves the following:
$rooms[$roomNumber]++;
So now let's go back to our original problem definition and see where we left off. We want to fill up the first room, then the second, then the third, etc.
So first we needed a way to define filling up a room. Well filling a room involves putting people in it (done) until it's full (not done). So now we need a way to check and see if a room is full.
if($rooms[$roomNumber] == 4)
should do nicely. So now we have a way of "filling a room until it's full"... But after this we need to start on the next room. This means we need to always know which room we are currently filling. If there's something new that we need to know, we need a new variable for it. Let's call this variable $roomNumber. We'll start with $roomNumber = 0; (the first room in the array) and continue until it's 5. Since there is no sixth room (element 5) then if $roomNumber ever becomes 5, we have too many people.
<?php
$rooms = array(0, 0, 0, 0, 0); // 5 empty rooms
$peopleNotInRoomsYet = 14; // We'll choose a number that won't divide evenly
$roomNumber = 0;
while($peopleNotInRoomsYet > 0){ // If there are people waiting...
if($rooms[$roomNumber] == 4){ // If the room is full...
$roomNumber ++; // Go to the next room
}
if($roomNumber == 5){ // If we are out of rooms...
die("Too many people!!!"); // die
}
$rooms[$roomNumber] ++; // Otherwise, add someone to the room
$peopleNotInRoomsYet --; // And remove them from the waiting list
}
?>
I know this was extremely length for the tiny amount of code we ended with, but I was attempting to explain the process of going from concept to code. Recognize the simple rules that you need to follow, then recognize the items you need to keep track of. Also remember that the solution I posted works only in the simplest situation, that being you don't need to know who is in the room, just how many people. It also assumes that no room starts with anyone in it. If room two started out full then this algorithm would fall apart since I didn't check for that. There are plenty of modifications left to be done by the reader, but this should get you pointed in the right direction.
This is not directly a PHP question, you should first describe the algorithm and then try to implement it.
From what I understand the best solution would be to keep a list of rooms sorted by actual empty spaces (so at the beginning you will have empty rooms, then rooms with 1 people, then rooms with 2, etcetera).
Then whenever a new user comes you have to choose a policy to assign it to a room, for example you could choose to always add the newcomer to a most empty room (so you will choose a random one between the empty ones, or between the rooms with just 1 people if no empty one is available and so on).. or you could decide to assign it to one random room which is not full. It depends on what you really need to do.
In anycase you could keep 2 lists of rooms, one for the not-full and one for the full rooms. When a room becomes full because a newcomer fills it you just swap it to the other list. When, instead, an user leaves a full room you switch it back to original list.
Of course keeping the not-full room list ordered by empty spaces is useful just when you policy needs to perform a choice that depends on how many empty spaces there are in any room, otherwise you could just keep all of them together and choose one randomly.