I am kind of new in programming generally and I found it a good idea to ask here first.
So, let's say I have about 900 sets of 6 numbers stored somewhere (maybe in arrays?). I want each time to generate a random set of 6 numbers that is different than the other 900. If it is the same (check with the other 900), then don't accept it and generate a new. I thought of using arrays and check the new set with the others each time, but I think it's a little "painful" to have 900 arrays before.
Any ideas would be appreciated! Thanks!
Honestly, I failed to imagine the task you need this for. )) But usually when you need to ensure a uniqueness of some sort of sets, you use hashes.
Let's say, for example, we have 900 arrays of the following structure:
$arr1 = [n1, n2, n3, n4, n5, n6];
$arr2 = [m1, m2, m3, m4, m5, m6];
...
And we need another array, which shouldn't be the same as any of these.
The solution, I think, is to create a metastructure for storing these arrays alongside its hashes. Something like...
$arrayCollection = array(
hash($arr1) => $arr1,
hash($arr2) => $arr2,
...
);
Then, when a new set is created, I'd generate its hash too - and just check whether the element with the same hash already exists in my collection. Like this:
do {
$newArr = generateArray();
$newArrHash = hash($newArr);
} while (isset($arrayCollection[$newArrayHash]));
It would be quite fast, much faster then just comparing these sets again and again. )
As for hash function, it can be as simple as...
function hash(array $arr) {
return implode('|', $arr);
}
... or you may need to wrap it into some digest function (md5($x, true) will do just fine, I suppose), if $arr may contain some very large strings/numbers.
Related
given I have an array, say:
$myArray=['12','AB','3C']
I want to return the value 2 (which is the length of each of the array elements indivudually.)
But in case I have something like
$myArray=['12','AB2','3C']
I want to stop the calculation/loop right after the second element of the array 'AB2' and let my function return null.
What is the most effective way to reach this in the matter of being performance and speed effective? Since such an array can get long.
Casual way
I think you are trying to stop the array loop the moment you get two different lengths in an element?
In that case, at worst, you'd need an O(n) runtime (since you need to verify every element, unless you have an abstract data type in mind in which case it could be O(1), if it is stored in the object property or you calculate the difference detected on the fly while pushing items into arrays)
Since the moment we discover an element is not the same length, we can simply quickly store the length of the first element in the array since we know if we detect any other length other than what we stored, we can immediately return null
function linear_loop($array) {
$len_of_first = strlen($array[0]);
foreach ($array as $val) {
if (strlen($val) != $len_of_first) {
return null;
}
}
//Function still running, entire array was same, return the length of first element
return $len_of_first;
}
This function is O(n) with each operation is constant. strlen is O(1)
Algorithmic complexity of PHP function strlen()
Most "performance-fastest"
Since you said that the array can get quite long, if you are not immediately generating the array, but rather you need to push items into it, then in your push operation, you can check before pushing it the item_to_be_pushed is the same strlen or whatever property you are trying to compare as the one you've stored (which can be picked arbitrarily, since the array must be of uniform some property)
In this case, you could have some object with property: uniform_length and store that. Then whenever you push into your array, you can check against it with the uniform_length. If it isn't the same length, then you can store in the object property called uniform as false. (By default uniform is true since if there is only one element in the array, it must be uniform).
This would be an O(1) calculation since it is stored as an attribute. But you probably don't need an object for something as simple as this, and you can just store it as some variable.
O(1) vs O(n) Runtime and why it is more performance effective
Since not everyone knows Big O, a quick explanation on what I said. O(1) runtime is "infinitely" better than O(n) runtime since the runtime of the function will not grow with input (as in processing 1 million items require the same amount of steps as processing 1 item)
Just loop through and return early when you find something that isn't correct. Don't worry about micro-optimizations until you have profiled and found that this function is really your bottleneck
ex.
function isCorrect($arr) {
$len = strlen($arr[0]);
for($arr as $val) {
if(strlen($val) != $len) {
return false;
}
}
return true;
}
Just my two cents. You could also use array_map for this:
$myArray = ['12','AB','3CC'];
$lengths = array_map('strlen', $myArray);
// output
Array
(
[0] => 2
[1] => 2
[2] => 3
)
you can just write an if statement and check the max($lengths) and return true or false
-Cheers
if I have some code like:
foreach(array_keys($array) as $key)
{
// work with the array
}
I have 2 questions
Is array_keys( ... ) called for every single iteration of foreach( ... )? Is it efficient?
If I was to compare speed and memory, is the code above faster/more efficient than
foreach($array as $key => $data )
{
// use $key only
}
1.) If array_keys($array) would be evaluated in every iteration, then i don't think, the position where you were last time could be remembered, since array_keys() would return a fresh array with keys every time, plus it would be really bad in terms of performance, so no. This goes for all expressions which evaluates as some form of iterable, and goes in the first part of a foreach.
2.) If you iterate on the whole array, then here is what happens:
a) array_keys() first extracts all the keys from your array, which kind of a mix of a List and a Hashmap (if you are familiar with java or some strongly typed oo language), and it might be really fast or really slow depending on the implementation of the arrays internal structure and the array_keys method. Then if you iterate on the array, you need to do a lookup in every iteration, like $value = $array[$currentlyIteratedKey]; which also needs some time, especially with string keys.
b) The foreach loop is a language construct (probably better optimized), and there is no additional lookup, you get the key and the value in every iteration, so i think it would be faster.
Hope it helps, correct me if I'm wrong!
1 - faster when use all array
2 - faster when need to "find" some key and break
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?
I am new to php. I was wondering how I could declare a static array in php. Here is what I would do in C. How is the corresponding php code for it?
char a[][] = { (1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3) };
From what I read it has to be something like this -
$a = array( 1 => array(1,1), 2 => array(1,2), ... );
Is this correct? If so it sucks :) I hope I am wrong.
Thanks,
- Pav
You've already found the way to do it natively.
Another option would be to declare your data as JSON (a very concise and human-friendly format). This could be either in a separate file bundled with your app, or directly in your code in a string. Then parse the JSON at runtime. Since PHP isn't exactly known for speed, this may or may not make your noticeably app slower to start.
you have it already figured out in your question.
One thing I would add is that you do not need to explicitly define the keys if you are intending to use a zero based array, this is assumed and can be done like so...
$a = array(array(1,1),array(1,2), ... );
You can also use what is called associative arrays which use string keys and you define them the same way you do in your example, except use strings instead of numbers...
$ass_array = array( 'array_1' => array(1,1), 'array_2' => array(1,2), ... );
you would then call your associative array like this...
$ass_array['array_1'];
Also, if you want to append single items to an array (for example in a loop to load an array)...
$ass_array[] = $item;
Further to jondavidjohn's anwser, you could just write a quick script to grab your list of values and generate the array statement for you.
No need to care how verbose the syntax is then. If the task is long and repetitious enough to care, don't do it by hand. :)
I'm trying to compare two entries in a database, so when a user makes a change, I can fetch both database entries and compare them to see what the user changed, so I would have an output similar to:
User changed $fieldName from $originalValue to $newValue
I've looked into this and came across array_diff but it doesn't give me the output format I need.
Before I go ahead and write a function that does this, and returns it as a nice $mtextFormatDifferenceString, can anyone point me in the direction of a solution that already does this?
I don't want to re-invent the wheel..
Since you require "from $originalValue to $newValue", I would go ahead and select the two rows, put them in assoc arrays, then foreach through the keys, saving the ones that aren't equal. Kind of like:
$fields = array_keys($row1);
$changedFields = array();
foreach ($fields as $field) {
if ($row1[$field] != $row2[$field]) {
$changedFields[] = $field;
}
}
I realize you were asking about the existence of pre-built wheels but I felt the solution was pretty simple.
?>
Although you didn't define what format you needed, but well-known diff algorithm is probably for you. Google for PHP diff algorithm and you'll find some suggestions I am sure.
You could get the changed values ($newValue) with array_diff_assoc and then just use the keys ($fieldName) to find the original value $originalValue and output it in anyformat you want