I am making a way to organize user into groups and need a way to check them. For example I have a method to check gender, which return true if there is no gender imbalance and false if there is. I also have similar methods to check age distribution and to check genders. For each of these methods I have a method which makes an optimized array of groups.
I.e. i have a method which optimizes groups based on gender. I would only call one of these methods if the respective check returns false. The problem I am running into is that when I optimize the groups based on a specific criterion i.e. gender, there is a chance that the new optimized groups have messed up another check criterion.
For example, if I check age, gender and skill level (my third check) and I find that there is an imbalance in age, proceed to optimize the groups with respect to age, then I could potentially mess up gender or skill level distributions. My solution to this problem was that If I could find a way call all variations of the check methods and break if a check all method returned true (all checks return true, all groups have good balances of age, gender and skill level).
Ex:
Let A, B and C be check methods and optimize_A, optimize_B, optimize_C be the make optimized group methods. I need some way loop through the check methods 3! times (because there are 3 check methods and I need to run ABC, ACB, BAC, BCA, CAB, CBA). OR I could do a while loop and break if the method check all () returns true (all checks return true, all have good distributions) and break once I have run the all the combinations of the check methods.
Could anyone help me with this problem? Please bear in mind I am a novice programmer and have never done anything like this before. Thanks
Edit:
How could I do something like this JavaScript code snippet in php?
var arr = [check1, check2, check3],
rand = Math.floor(Math.random() * arr.length),
func = arr[rand];
func();
Here is my attempt:
<?php
$checks_to_run = array('check_gender','check_age','check_skill_level');
$rand = floor(rand(0, count($checks_to_run) - 1));
$func = $checks_to_run[$rand];
echo $this->.$func.($tmp); // $tmp is an array of groups
?>
You almost had it, just remove the dots at the end.
$checks_to_run = array('check_gender','check_age','check_skill_level');
$rand = floor(rand(0, count($checks_to_run) - 1));
$func = $checks_to_run[$rand];
echo $this->$func($tmp); // $tmp is an array of groups
Related
trying to make a tic-tac-toe game actually. So if there's a better way I would like to know too!
So I have a grid [0,8], and the user's positions are stored in an array. Great.
Next I want to see if the columns match up. So let's say first row is (0,1,2).
My question is if the user has an array like array(1,5,6,0,2), so he won. How can I match it efficiently?
I was thinking of doing something like this but doesn't look efficient:
$user= array(1,5,6,0,2);
in_array(0,$user) && in_array(1,$user) && in_array(2,$user)
I also thought about switch case but still face the question how do I find multiple values at once.
I agree that with such a small number of possible combinations to win, the solution can be kept very simple. I would do it using array_diff.
function has_won($user) {
// returns false if the user has not won, otherwise
// returns the first winning combination found.
$wins = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];
foreach ($wins as $win) {
if (!array_diff($win, $user)) return $win;
// array_diff returns the values in the first argument
// not present in any subsequent arguments. So if its
// result is empty, the user has winning combination.
}
return false;
}
I will not make a claim that this is the most efficient method, but it reduces the number of operations considerably compared with && chaining and multiple in_array() calls.
What we'll do is keep a 2-dimensional array of possible win-combinations: rows, columns, diagonals, as sub-arrays. Then in a foreach loop over that 2D array, test the user's current array state against the row combination with array_intersect(). If the entire winning combination is present in the user's array, the result of array_intersect() will be 3, which you can test with count().
Since one match is enough for a win, you can break out of the loop on the first match to declare a win.
$combinations = array(
// Rows
array(0,1,2),
array(3,4,5),
array(6,7,8),
// Columns
array(0,3,6),
array(1,4,7),
array(2,5,8),
// Diagonals
array(0,4,8),
array(2,4,6),
);
// Loop over the array of winners and test array_intersect()
// If 3 values intersect, the full win combination was matched
foreach ($combinations as $combination) {
if (count(array_intersect($combination, $user)) == 3) {
// User wins! Take whatever action necessary...
// Exit the loop
break;
}
}
Here's a demonstration in which 2 of 3 sets for $user are winners: http://codepad.viper-7.com/Mvu0wa
There are algorithmic ways of generating the winning combinations rather than hard-coding them, but there are only eight possible combinations so it isn't that hard, and the point here is the use of array_intersect() to find a subset of the user's current placements.
So, I'm trying to make a gladiator game, where the players will be lanistas. I'm going for realism, so the gladiators will die in the arena, making a big influx of new "recruits" necessary.
For now, each newly created gladiator has 21 attributes, ranging from numerical values for things such as strength and agility, to text for faction and name. These are calculated by random functions. Names and factions I'm picking randomely from arrays with (at least for names) a relatively big list of realistic names. Numerical values are simply rand(x,y).
Before I added the name and faction arrays, I tried several times running the file that create gladiators with a while loop creating 10000 gladiators, without any clones emerging, as far as I could see. Now, with picking names too from random (as described above), everything works fine if I create a small number of gladiators, but once I use a number of a couple of hundred for my while loop, or if I run the file a few times in a row with as low a number as 50 in my while loop, I get clones.
With 21 attributes, 100 different values+ for most of them, getting clones doesn't happen by chance. Can anyone tell me what's wrong? This can kill my game, and I was just getting optimistic after overcoming a few (easy) challenges.
Oh, and yeah, the gladiators with the attributes are put into a mysql database automatically.
Edit (update):
I went back in my stuff, removed the naming and faction random functions, and set all to "s". Created 10000 gladiators named s s from faction s, and it seems there are excactly 0 clones - nobody with the exact same stats.
Reactivated the random name functions. Ran the file, creating 200 gladiators. Couldn't see clones. Ran it again. One clone for each gladiator. And again. Now two clones for the gladiators.
This random function isn't random at all, is it?
Edit (update 2):
Tested it again, with one of the previously excluded random functions activated one at a time. It seems its the firstname and surname functions that are screwing things up. Also, from my last test, it seems like there's a pattern, with gladiator id 209 being equal to 737, 77 being equal to 605 and 1133, 148 equal to 676, 772 equal to 244, and so on.
737-209, 605-77, 1133-605, 676-148, 772-244 all have one thing in comon. They all equal 528.
This isn't much random at all.
The function I use for getting names goes something like:
$surname=surname($faction) //surname is a function, using the variable $faction
function surname($faction) {
if ($faction=="Roman") {
$nomen = array("Aburius", "Accius", [...]);
$cognomen = array("Zeno", "Zonsimus", [...]);
$randnomen=array_rand($nomen,1);
$randcognomen=array_rand($cognomen,1);
$merge=array($nomen[$randnomen],$cognomen[$randcognomen]);
$surname=implode(" ",$merge);
return $surname;
}
To clarify: The [...] in the $nomen and $cognomen arrays is there in place of hundreds of roman names, to save space and your time.
array_rand seems to have a problem with randomness see here.
I prefer to use mt_rand myself.
The following function can create random names with either1,2 or three parts.
function randomName(){
$numargs = func_num_args();
$first = func_get_arg(0);
$one = count($first)-1;
$name = $first[mt_rand( 0,$one)]; //count($array)-1
if($numargs > 1){
$middle = func_get_arg(1);
$two = count($middle)-1;
$name .=" ". $middle[mt_rand( 0,$two)];
}
if($numargs > 2){
$last = func_get_arg(2);
$three = count($last)-1;
$name .= " ".$last[mt_rand( 0,$three)];
}
return $name;
}
USE
$var= randomName($first,$middle,$last);// 3 names
$var= randomName($first,$last);// 2 names
etc
WHERE $first,$middle,$last are arrays
With only ~100 values for an attribute and 1000s of gladiators, there may be many with the same name attribute, for example.
If you mean that there may be multiple gladiators where all 21 attributes are the same, then the only way to guard against that is to check newly created gladiators against the existing ones and if there is a match regenerate the new one.
Just like you would when someone registers for a site, normally username and email address must be unique per user, so you have to check first.
The easiest and most performant in this case might be to generate a "hash" of each gladiator's properties and check if it exists before generating a new gladiator. This will make them all unique, so you also need to consider how unique do you want them? Can 2 or more gladiators have 20 properties in common? How about 15, etc?
Background:
I am creating a method to pull information from one table, check if it exists in a second table, and if it doesn't then insert the information. While comparing the data, the check must first see if the name matches, and then proceed to check if the account number matches the corresponding name. This code is heavily commented so a step by step process can be followed as well. I am greatly appreciative of all the help the masters of stackexchange bring to the table, so after scratching my head for a while, I bring my issues to the table.
Apparently my code is breaking when it goes to check the account number, even though a matching name exists. According to my best skills, all the code should work perfectly.
As you will be able to see through the print_f of all_validation_names, as well as all_validation_accounts, the information of the first passing statement is contained in the array with a check.
My question is as follows: Why can't a varchar variable, stored in an array with a corresponding key ($check_account_number) be passed into in_array. The function always returns else, where although the variable is "1", it isn't found using the corresponding key in $all_validation_accounts.
Please help!
Code For The Processing Of The Script
if (in_array($check_agency_name,$all_validation_names))
{
//Set a marker for the key index on which row the name was found
$array_key= array_search($check_agency_name, $all_validation_names);
//Now check if the account corresponds to the right account name
if (in_array($check_account_number,$all_validation_accounts["$array_key"]))
//NOTE: i've even tried strict comparison using third parameter true
{
//Bounce Them If the Account Matches with a name So theres no duplicate entry (works)
}
//If the account doesn't correspond to the right account name, enter the information
else
//ALSO DOESNT WORK: if (!(in_array($check_account_number,$all_validation_accounts["$array_key"])))
{
// The account doesn't exist for the name, so enter the information
//CODE TO ENTER INFORMATION THEN BOUNCE (works)
break;
}
}
The Output:
Passing Name to match: a And Account:1
There are accounts existing, so heres all the validation arrays:
all_validation_names: Array (
[0] => a
[1] => a
[2] => b
)
all validation accounts: Array
(
[0] => 1
[1] => 2
[2] => 2
)
the system found check_agency_name in the array all_validation_names,
so lets check the account number with this key: 0
the account name existed, but the system didn't find the account
number match, so it must enter it as if the account never existed
heres the information that should be entered: used_selector: 0
agency_name:A address: city: state: zip: account_number: 1
now the system should enter the info, and bounce the client out
This is not an answer. Your code is full of redundancies and is extremely difficult to read. You need to do a lot more work on your own to narrow down the issue before you come to SO for assistance. It's unlikely anyone will have the patience to step through your code, especially since they also can't run it without having a copy of your invisible database.
However, I felt obligated to tell you that your __trim() function is poorly named and far too complicated for what it does. It is not a "trimmer", since unlike the real trim() it removes characters from the "inside" of strings as well as the ends. And your implementation is far too complex.
It is the same as this one-line function:
function __trim($str, $charlist=" \t\r\n\0\x0B") {
return str_replace(str_split($charlist), '', $str);
}
Once I saw that forty-line __trim function I lost the will to read any more code in the question.
Update
You've narrowed down your question, good. I'll attempt to infer the state of the program at this point. (This is something you should have done for us....)
Slimming your code to very minimum:
if (in_array($check_agency_name, $all_validation_names)) {
$array_key = array_search($check_agency_name, $all_validation_names);
if (in_array($check_account_number, $all_validation_accounts["$array_key"])) {
error_log('IF-BRANCH');
} else {
error_log('ELSE-BRANCH');
// break; // Removed because it makes no sense here.
}
}
Let's see what the values of these vars are:
$check_agency_name = 'a'
$all_validation_accounts = array(1, 2, 2);
$all_validation_names = array('a', 'a', 'b');
$array_key = "0";
$check_account_number = ???
You haven't told us what $check_account_number is. However we still know enough to see at least one thing that is wrong. The following lines are all the same (just replacing variable names with values):
in_array($check_account_number, $all_validation_accounts["$array_key"])
in_array($check_account_number, $all_validation_accounts["0"])
in_array($check_account_number, $all_validation_accounts[0])
in_array($check_account_number, 1)
Here we see that regardless of the value of $check_account_number, in_array() will return false because its second argument is not an array!
(By the way, don't quote key lookups: $all_validation_accounts[$array_key] is more straightforward--the quoting accomplishes nothing except to obscure your intent.)
This code would also produce an error Warning: in_array() expects parameter 2 to be array, integer given in /file/name.php on line ##. This points you to the problem right away, and you would have seen it if you had checked your error logs. Set your PHP error reporting very high (E_ALL | E_STRICT), watch your error logs, and make sure your program does not produce any error output while running normally. If you see anything, fix your code.
Warning: this is not the answer to the question
Lets start from your trim on steroids:
Better optimize it with in built php functions as follows:
function __trim($str, $charlist = '') {
$result = '';
/* list of forbidden chars to be trimmed */
$forbidden_list = array(" ", "\t", "\r", "\n", "\0", "\x0B");
if (empty($charlist)) {
for ($i = 0; $i < strlen($str); $i++){
if(!in_array($str[$i],$forbidden_list))$result .= $str[$i];
}
} else { // else means in case if (condition) was not met
for ($i = 0; $i < strlen($str); $i++) {
if(strpos($charlist, $str[$i])===false)$result .= $str[$i];
}
}
return ($result);
}
Ritual Lecture
Stop using mysql. It is deprecated. Using it means inviting trouble.
I have answered my own question by rethinking the logic behind the checks.
Thank you for all your responses.
Here is a link to the solution. I have posted it online to share as well as optimize, because all the great minds of SO deserve it!
https://stackoverflow.com/questions/15775444/entry-of-items-checking-sharing-optimization-from-post-form
Hey guys, been having this problem for a while now, and can't for the life of me seem to track down anything remotely helpful.
I'm trying to, once a user logs into the application (using the built-in Auth component), use the school_id field to find the name of the school that they are associated with (and display this name in the header of the view). I also figure that I will need to call up various other pieces of school information in other actions down the road.
I've tried both of the following, but neither seems to work. No matter whether I School->find() based on the user's "school_id" or by a number that I have included manually. It simply returns the information of the same school every time (the school with the ID of 1).
Here's what I've tried:
$this->set('school_name', $this->School->find('first', array('conditions' => array('School.id' == 2))));
$this->set('school_info', $this->School->find('first', array('conditions' => array('School.id' == $this->Auth->User('school_id')))));
$this->set('school_info', $this->School->find($this->Auth->User('school_id');
Once again, not a problem with the code not returning anything. It just returns the same school every time (where ID = 1).
As you can imagine, this has been fairly frustrating, and I would love any help that you could provide.
Thanks,
Ben
You are using the == sign instead of => in your condition.
It should be:
$this->School->find('first', array('conditions' => array('School.id' => 2))));
Remember: == is a conditional operator. => is the arrow notation used to create array key-value pairs.
A short way to do it would be:
$this->School->findById($this->Auth->user('school_id'));
If you're supplying the id, supply it to the findById and not the all-encompassing find method. That said, you should still take care to see that you're using the right operators. :)
Quick Note: 'School.id' == 2 evaluates to false and array(false) is an array with one element false which is why you didn't get any errors.
The reason I am asking this question is because I have landed my first real (yes, a paid office job - no more volunteering!) Web Development job about two months ago. I have a couple of associates in computer information systems (web development and programming). But as many of you know, what you learn in college and what you need in the job site can be very different and much more. I am definitely learning from my job - I recreated the entire framework we use from scratch in a MVC architecture - first time doing anything related to design patterns.
I was wondering what you would recommend as the best way to pass/return values around in OO PHP? Right now I have not implement any sort of standard, but I would like to create one before the size of the framework increases any more. I return arrays when more than 1 value needs to get return, and sometimes pass arrays or have multiple parameters. Is arrays the best way or is there a more efficient method, such as json? I like the idea of arrays in that to pass more values or less, you just need to change the array and not the function definition itself.
Thank you all, just trying to become a better developer.
EDIT: I'm sorry all, I thought I had accepted an answer for this question. My bad, very, very bad.
How often do you run across a situation where you actually need multiple return values? I can't imagine it's that often.
And I don't mean a scenario where you are returning something that's expected to be an enumerable data collection of some sort (i.e., a query result), but where the returned array has no other meaning that to just hold two-or-more values.
One technique the PHP library itself uses is reference parameter, such as with preg_match(). The function itself returns a single value, a boolean, but optionally uses the supplied 3rd parameter to store the matched data. This is, in essence, a "second return value".
Definitely don't use a data interchange format like JSON. the purpose of these formats is to move data between disparate systems in an expected, parse-able way. In a single PHP execution you don't need that.
You can return anything you want: a single value, an array or a reference (depending on the function needs). Just be consistent.
But please don't use JSON internally. It just produces unnecessary overhead.
I also use arrays for returning multiple values, but in practice it doesn't happen very often. If it does, it's generally a sensible grouping of data, such as returning array('x'=>10,'y'=>10) from a function called getCoordinates(). If you find yourself doing lots of processing and returning wads of data in arrays from a lot of functions, there's probably some refactoring that can be done to put the work into smaller units.
That being said, you mentioned:
I like the idea of arrays in that to pass more values or less, you just need to change the array and not the function definition itself.
In that regard, another technique you might be interested in is using functions with variable numbers of arguments. It is perfectly acceptable to declare a function with no parameters:
function stuff() {
//do some stuff
}
but call it with all the parameters you care to give it:
$x = stuff($var1, $var2, $var3, $var4);
By using func_get_args(), func_get_arg() (singular) and func_num_args() you can easily find/loop all the parameters that were passed. This works very well if you don't have specific parameters in mind, say for instance a sum() function:
function sum()
{
$out = 0;
for($i = 0; $i < $c = func_num_args(); $i++) {
$out += func_get_arg($i);
}
return $out;
}
//echoes 35
echo sum(10,10,15);
Food for thought, maybe you'll find it useful.
The only thing I'm careful to avoid passing/returning arrays where the keys have "special" meaning. Example:
<?php
// Bad. Don't pass around arrays with 'special' keys
$personArray = array("eyeColor"=>"blue", "height"=>198, "weight"=>103, ...);
?>
Code that uses an array like this is harder to refactor and debug. This type of structure is better represented as an object.
<?php
Interface Person {
/**
* #return string Color Name
*/
public function getEyeColor();
...
}
?>
This interface provides a contract that the consuming code can rely on.
Other than that I can't think of any reason to limit yourself.
Note: to be clear, associative arrays are great for list data. like:
<?php
// Good array
$usStates = array("AL"=>"ALABAMA", "AK"="ALASKA", ... );
?>