Eliminating Repetition in a Randomized Matrix - php

I am writing a program that involves placing one number into each cell of a 7x7 grid. There are 56 numbers, chosen from at random, and there must be no repetition.
The end result should be a 7x7 grid in which each cell contains an integer from 1 to 56, with no two cells containing the same number. What is the most efficient way of doing this?
extra words:
I tried creating a for x{for y{}} that would go through the grid cell by cell and add a random number 1-56. It would then check a 56-slot array to see if that number was already in use, and correspondingly either re-roll or accept the number, then flag the array to mark the number as in use. For some reason, I couldn't get it to work, and it seemed like a bad solution. I scrapped it, and instead had a second for x{for y{}} run each time and check the entire grid cell by cell for the rolled number before approving or rejecting it. This also didn't quite work and seemed unwieldly, so I scrapped it as well.

You can generate an array of 1:56, then shuffle, then pick out the first 49 elements.
$arr = range(1,56);
shuffle($arr);
$vals = array_slice($arr, 0, 49); //49 because grid is 7x7
// put $vals in grid.

Create an array of length 56, filled with numbers 1 to 56
Use Fisher-Yates shuffle to create an unbiased, randomised array
Fill 7x7 matrix (row or column order) sequentially from array.

Create an array of 56 elements containing the numbers 1 to 56.
Generate a random number between 1 and the length of the array
Choose the number at that index and remove it from the array
lather, rinse, repeat

Create an array with all the numbers needed, and shuffle it.
$fullGrid = range($min, $max);
shuffle($fullGrid);
Now all you need to do is visually display the $fullGrid array.
More on the php shuffle function.

Related

How to sort numbers containing current year in prefix

I am having trouble sorting the job numbers in my project.
My client requirement is to store the job numbers in the below format:-
current year-1, current year-2, current year-3, and so on...
For example:-
The current year is 2021 so the job number will be like this:-
21-1, 21-2, 21-3, 21-4, and so on...
When the year changes it should start again from 1 and so on for the next year.
For example:-
22-1, 22-2, 22-3, 22-4, and so on...
I had stored the job numbers in the above format successfully but I am unable to sort the job numbers in the correct way as required by the client.
I had sorted the data in this way:-
21-1, 21-10, 21-100 to 21-109, 21-11 to 21-19, 21-2 and so on...
but the actual sort should be like this:-
21-1, 21-2, 21-3, 21-4...21-10, 21-11 to 21-99, 21-100 to 21-199 and so on...
And if the year changes then:-
22-1, 22-2, 22-3, 22-4...22-10, 22-11 to 22-99, 22-100 to 22-199 and so on...
I hope I have explained my problem briefly. Please help me in sorting out the job numbers.
I assume you need the sorting to occur in your database because you're paging or just otherwise not holding all results in application memory, use use the following sql order by clause:
select my_column
from my_table
order by left(my_column, 2),
len(my_column),
right(my_column, len(my_column) - 2)
Explanation:
left(my_column, 2), numerically sort first two digits so years are grouped together.
len(my_column) group record sequence based on magnitude (i.e., xx-100 appears after xx-2 because it's longer).
right(my_column, len(my_column) - 2) numerically sort record sequence.
Hint: This assumes your year-code is always exactly two digits. I could have found the index of the dash instead, but that feels even more presumptive.
If you require an application-side (PHP) solution, you can use natsort. From W3Schools:
Definition and Usage
The natsort() function sorts an array by using a
"natural order" algorithm. The values keep their original keys.
In a natural algorithm, the number 2 is less than the number 10. In
computer sorting, 10 is less than 2, because the first number in "10"
is less than 2.
Syntax
natsort(array)
21-1, 21-10, 21-100, 1, 10, 100
These are your ids from the database. At first, declare an empty array and a variable for serial then loop through the objects. Push every object with two new keys array["date_serial"], array["serial"]. Then take the new array and then display the result by sorting the array by "serial" key or asc or desc order.

Accessing unique value pairs from an array without repeating myself

I am trying to access unique value pairs from an array in a random order - without repeating myself until I have to.
For example, if I have an array set A,B,C,D (generally an even number of items, but up to 20) then the first time through I might pair A-B & C-D. But I want to guarantee that the next time I do it, I avoid repeating my pairing and that I get both A-C & B-D and A-D and B-C before I then get A-B and C-D again. Each item should only be called once in each round.
I started off by shuffling the order of the array randomly then pairing two values together - but I need a way to prevent some pairings from occurring more frequently than others (ideally I'd want them to increment equally all the way through).
So I've moved to looking at permutations - and have managed to get a full array containing all the possible pairings using the code below:
$this->items = array('A','B','C','D');
$input = $this->items;
$input_copy = $input;
$output = array();
$i = 0;
foreach($input as $val) {
$j = 0;
foreach($input_copy as $cval) {
if($j == $i) break;
print $val.'-'.$cval.'<br/>';
//$output[] = array($val => $cval);
$j++;
}
$i++;
}
//print_r($output);
e.g for A, B, C, D I get:
b-a
c-a
c-b
d-a
d-b
d-c
I want to cycle through the set n-1 times and capture the results in another array, but I'm not sure how to generate the actual order from these unique options
In other words, I want to turn the list above in to the below:
1st run =>
1=> A-B,
2=> C-D,
2nd run =>
1=> A-C,
2=> B-D,
3rd run =>
1=> A-D,
2=> C-B,
It may be that I can do this more simply from $this->items. I've also had a look at the Math_Combinatorics PEAR package, but I wasn't sure where to start.
I'd be grateful for any help!
You can use round-robin tournament algorithm
Place elements in two rows.
Fix one element - in this case A
For next round shift all other elements in circular manner.
Pair them.
Repeat N-1 times
A B
D C
-----
A D
C B
----
A C
B D
----
I assume that you want to generate each pairing exactly once, i.e. each partition of your whole sequence into pairs. If you only want each pair exactly once, that's a different problem handled in a different answer.
Think about this problem recursively: At the beginning you have n elements. From these, take the first and choose a partner for it from the remaining n-1 elements. Take this pair out of the list and recuse with the remaining n-2 elements. If you make each choice unbiased, the remaining pairing will be unbiased as well. But that doesn't guarantee you won't repeat yourself earlier than neccessary.
If you really want to be sure you avoid repeating pairings, you should first think about how many possible pairings there are. For now I'll assume that n is even, so you only have complete pairs. It's easy to adjust this to odd n with one unpaired element. To obtain the total number of possible pairings, you have to multiply your choices:
m=(n-1)*(n-3)*(n-5)*...*7*5*3*1
So it's a product of odd numbers. That's A001147, also written as a double factorial m=(n-1)!!. Note that these numbers grow fairly quickly, so even for moderate n (like n=16) you might not have to worry about repeating yourself simply because there are so many possible pairings to choose from that a repetition is fairly unlikely.
If you really want to be sure that you avoid repetitions, you could of course simply generate the whole list and shuffle it. But as I just indicated, that list could become huge as well. So instead I'd suggest you divide this problem into two steps. Find a way to generate all numbers from 0 to m-1 each exactly once, and find a way to turn such numbers into pairings. For the latter, you can simply decompose your number step by step. At each step, take index % (n-1) to make the current choice, and choose (int)(index / (n-1)) as the index for subsequent choices in the recursive calls.
For the former, the easiest thing I can think of would be using a PRNG with a prime number p>m as its period. Using modular arithmetic, that should be easy to do. Then simply discard all values which are greater or equal to m. Discarding means that you skip to the next element in the sequence. This will give all pairings in an order which should seem fairly random. If the starting point in that sequence should be random, be sure that if you at first choose a value which is to be discarded, then you have to initialize again, not skip to the next element. Otherwise some elements would be more likely as starting points than others.

Generating unique fixed integer ids from array of ids

So here is the situation... I got array of objects, each marked with unique integer id, and for each and every combination of those objects, I need to create new ones, each with unique ids. Problem is that that list of objects is dynamic, used in stateless environment, so newly generated ids must be same for every run.
To make it clearer what I need here, consider that array of objects as array of their ids, for example: [10, 7, 23]. And basically, I need to get ids for all the possible combinations:
10, 7
10, 23
7, 23
10, 7, 23
What's important here is that generated ids must be same for each distinct combination (for example: 10 and 7 should always produce same id). Also, newly added objects should not affect previously generated ids. So for example, when some new object is later on added to that list, ids generated from previous combinations must remain the same as before new object was added.
Currently, I have a solution that pretty much comes down to generating new id as a result of the sum of combining ids, so resulting ids are:
17
33
30
40
Of course, this approach can produce duplicate ids, and that's the reason I'm asking for advice for some more sophisticated algorithm. I also tried introducing fixed offset of 1000 for newly generated ids and multiplying sum with number of objects in combination, so that for example resulting ids are 1034 (1000+(10+7)*2), 1066 (1000+(10+23)*2), etc., but I'm not sure that it would save me from duplicates. :)
Clear mention, I need this for the purpose of certain PHP project, but as this problem is not language-specific, I hope that there are some good mathematicians that can bring some good solution. :)
Useful information is fact that combining ids are in range from 10000-99999 and maximum number of items in combination does not exceed 10.
Please note that I do not need solution for how to make all the combinations from array elements, but only that "formula" for producing integer id.
Thanks in advance.
Not really sure what your aim is, but I'll have a go...
Have you tried using character keys? For example 10, 7, 3 becomes a sequence with an underscore. Each sequence will have a unique hash.
$arrayOfKeys = array(10, 7, 3);
$hash = implode('_', $arrayOfKeys);
print $hash;
# 10_7_3
Personally I'd go for this simple approach. If you're using a database and you're not producing, say, 100k records per day, it should be pretty fast using an indexed (primary key or unique) varchar field.
If you are to create numbers, here a tip: take the length of the largest number and that will be the prefix of your sequence, e.g.:
10, 5, 1 -> 2100501
105, 45, 201 -> 3105045201
The prefix will tell you what the length of the following sequences are. I can't think of any way you'd get doubles... Anyone? ;)
Hope it helps...
Step 1: Sort the values you get.
eg: if you get 10, 7 or 7, 10 it should result result in 7, 10 before going to the ID generator. If you know the range of your numbers i.e lets assume [0-100] use radix or count sort, will be fast.
Step 2 : Represent the numbers as strings, seperated by any chosen seperator.(':') maybe.
eg: for 7, 10 id will become "7:10".
Sorting is being done to avoid generating different ID's for 10, 7 and 7, 10.
BTW What do these numbers represent?
I don't think this is possible unless you allow labels of increasing length.
Assume you have a maximum of N distinct objects, corresponding to N distinct labels.
If you want to be able to represent all possible pairs, assuming order in a pair does not matter, you potentially need N.(N-1)/2 extra labels, whatever they are, and you need to reserve them all.
And for all triples, N.(N-1).(N-2)/6, for all quads N.(N-1).(N-2).(N-3)/24...
This grows exponentially and will very quickly exceed the capacity of integers.
Any other solution that tries to compress the space of labels, such as hashing, will result in collisions. You can resolve the collisions by maintaining collision table, but this will break the "generated ids must be same for every run" requirement.

PHP MySQL insert values from multiple checkboxes into one column in table

I have a form that a user would fill out while creating a ticket for a bug they have found on our website. In the form there is currently an input field where the user would enter in the designs that the bug is affecting (ex., "Design1, Design2, Design3, Design4" ...etc). When the form is submitted the value is stored in a table column named affectedDesigns.
What i am wanting to do is create several checkboxes (one check box for each design we have) that a user would select instead of using the input field. They would be able to select all that apply. If possible i would still like to store all of the values into the affectedDesigns column in one record. I'm thinking that i can gather the selected checkboxes values and create an array or some comma delimited value that contains all of the selected items and submit that to the databasein the one record in the affectedDesigns column. How can i achieve this?
Also, how would i then pull that data and re-populate the checkboxes if they would like to go back later and edit the ticket? Thanks for any help!
I would avoid to store all values within a single field. You'll have a lot of problems once you'll have to do some query because you violate normalization rules.
create an array from your $_POST values keyed on the name of each checkbox, then just serialize that array before insert.... then you can unserialize it when you load it up again
You'll end up using explode() and implode() to convert between string and array.
You need the same answer I'm looking for.
Sprites in Basic language used that system for you to select the bits you wanted ON or OFF for each column (3 cols each sprite: 24 bites), and the sum of all the 8 values gives exactly the unique value that only that combination of elements on/off can give.
The KEY is that each elements adds a value that always is greater than ALL the other previous values added up together.
I.g. Checkboxes values are 1, 2, 4, 8, 16, 32, 64, 128.
E.g. If 3rd and 5th elements are selected (values 4 + 16) the result, 20, will only be obtained by those elements, since the next value 32 is greater than the sum itself and even if you sum up all the values up to the 5th element (value 16) the result will never reach 32 (it will always be 1 less than the next possible value, in this case adds up 31)
Basic language used to do it automatically, and it was easy since the max value was fixed. Each sum was only 8 values long. You need a maximum value to be input to your function to limit the attempts the script would make to "try".
So, THIS is what you need, I just don't know the name.
As soon as I find the name of this technique / math operation I'll post a working function here.
You could also get a binary number with the options, e.g. 01001001011 and then just use the character position to figure out whether that checkbox is on or off.
PS. What kind of answer is "you'll end up using explode or implode"?? That's the answer of the lazy fortune reader. "you'll eat and bleep until you die" :S
Lazy solution: assuming nothing else depends on the IDs of entries in affectedDesigns, just delete all entries for that ticket, then re-enter the submitted $_POST values.
The answer was right in the binary option.
It happens to be that a decimal number converted to binary, gives you EXACTLY the combination of options you need. Ones for the "selected" option and Ceroes for the options not selected (read right to left)
So the trick to save them is easy.
Assign each checkbox a value of 2^index, where index is your checkbox id/order
… and you'll get
2^index0 = 1
2^index1 = 2
2^index2 = 4
2^index3 = 8
…and so on.
Then, you sum up your checkbox values, let's say
$options_dec = sum($_POST['options']); //outputs 5 if options 0 and 2 are selected
That decimal sum, converted to binary shows you exactly which checkboxes were selected:
$options_bin = base_convert ( $options_dec, 10, 2 ); //outputs 0101 (reads right to left)
Now you can convert it to an array, reverse it, and call each matching its index with your checkboxes.
$options_arr = array_reverse( str_split( $options_bin, 1 ) ); //returns array containing "0,1,0,1"
Now populate your checkboxes with a loop. Assuming the checkboxes come in the same order than stored values, and each have a 2^$i.
for($i = 0; $i < sizeof($options_arr); ++$i) {
$checkbox_value = pow ( 2 , $i );
$checked_val = ( $options_arr[$i] ? 'checked' : '');
echo "<input type='checkbox' value='$checkbox_value' $checked_val />\n";
}
Not tested, since I made my version in JavaScript.
Another solution is to grab the option right from the binary string
$checked_val = (boolean) substr( $options_bin , -($i+1), 1 );// +1 because neg substr counts from 1, not 0
If being human readable in the database is not important you could use the PHP serialize function to combine all the rows into one storable string object.
If you want the data in the database to be readable, you could use implode/explode to convert your array to a single string and store as is in a char datatype.
Or if you want the data to be more managable and be able to do queries on it, I would store the checkboxes using the mysql SET datatype rather than a string.

Permutations of Varying Size

I'm trying to write a function in PHP that gets all permutations of all possible sizes. I think an example would be the best way to start off:
$my_array = array(1,1,2,3);
Possible permutations of varying size:
1
1 // * See Note
2
3
1,1
1,2
1,3
// And so forth, for all the sets of size 2
1,1,2
1,1,3
1,2,1
// And so forth, for all the sets of size 3
1,1,2,3
1,1,3,2
// And so forth, for all the sets of size 4
Note: I don't care if there's a duplicate or not. For the purposes of this example, all future duplicates have been omitted.
What I have so far in PHP:
function getPermutations($my_array){
$permutation_length = 1;
$keep_going = true;
while($keep_going){
while($there_are_still_permutations_with_this_length){
// Generate the next permutation and return it into an array
// Of course, the actual important part of the code is what I'm having trouble with.
}
$permutation_length++;
if($permutation_length>count($my_array)){
$keep_going = false;
}
else{
$keep_going = true;
}
}
return $return_array;
}
The closest thing I can think of is shuffling the array, picking the first n elements, seeing if it's already in the results array, and if it's not, add it in, and then stop when there are mathematically no more possible permutations for that length. But it's ugly and resource-inefficient.
Any pseudocode algorithms would be greatly appreciated.
Also, for super-duper (worthless) bonus points, is there a way to get just 1 permutation with the function but make it so that it doesn't have to recalculate all previous permutations to get the next?
For example, I pass it a parameter 3, which means it's already done 3 permutations, and it just generates number 4 without redoing the previous 3? (Passing it the parameter is not necessary, it could keep track in a global or static).
The reason I ask this is because as the array grows, so does the number of possible combinations. Suffice it to say that one small data set with only a dozen elements grows quickly into the trillions of possible combinations and I don't want to task PHP with holding trillions of permutations in its memory at once.
Sorry no php code, but I can give you an algorithm.
It can be done with small amounts of memory and since you don't care about dupes, the code will be simple too.
First: Generate all possible subsets.
If you view the subset as a bit vector, you can see that there is a 1-1 correspondence to a set and a binary number.
So if your array had 12 elements, you will have 2^12 subsets (including empty set).
So to generate a subset, you start with 0 and keep incrementing till you reach 2^12. At each stage you read the set bits in the number to get the appropriate subset from the array.
Once you get one subset, you can now run through its permutations.
The next permutation (of the array indices, not the elements themselves) can be generated in lexicographic order like here: http://www.de-brauwer.be/wiki/wikka.php?wakka=Permutations and can be done with minimal memory.
You should be able to combine these two to give your-self a next_permutation function. Instead of passing in numbers, you could pass in an array of 12 elements which contains the previous permutation, plus possibly some more info (little memory again) of whether you need to go to the next subset etc.
You should actually be able to find very fast algorithms which use minimal memory, provide a next_permutation type feature and do not generate dupes: Search the web for multiset permutation/combination generation.
Hope that helps. Good luck!
The best set of functions I've come up with was the one provided by some user at the comments of the shuffle function on php.net Here is the link It works pretty good.
Hope it's useful.
The problem seems to be trying to give an index to every permutation and having a constant access time. I cannot think of a constant time algorithm, but maybe you can improve this one to be so. This algorithm has a time complexity of O(n) where n is the length of your set. The space complexity should be reducible to O(1).
Assume our set is 1,1,2,3 and we want the 10th permutation. Also, note that we will index each element of the set from 0 to 3. Going by your order, this means the single element permutations come first, then the two element, and so on. We are going to subtract from the number 10 until we can completely determine the 10th permutation.
First up are the single element permutations. There are 4 of those, so we can view this as subtracting one four times from 10. We are left with 6, so clearly we need to start considering the two element permutations. There are 12 of these, and we can view this as subtracting three up to four times from 6. We discover that the second time we subtract 3, we are left with 0. This means the indexes of our permutation must be 2 (because we subtracted 3 twice) and 0, because 0 is the remainder. Therefore, our permutation must be 2,1.
Division and modulus may help you.
If we were looking for the 12th permutation, we would run into the case where we have a remainder of 2. Depending on your desired behavior, the permutation 2,2 might not be valid. Getting around this is very simple, however, as we can trivially detect that the indexes 2 and 2 (not to be confused with the element) are the same, so the second one should be bumped to 3. Thus the 12th permutation can trivially be calculated as 2,3.
The biggest confusion right now is that the indexes and the element values happen to match up. I hope my algorithm explanation is not too confusing because of that. If it is, I will use a set other than your example and reword things.
Inputs: Permutation index k, indexed set S.
Pseudocode:
L = {S_1}
for i = 2 to |S| do
Insert S_i before L_{k % i}
k <- k / i
loop
return L
This algorithm can also be easily modified to work with duplicates.

Categories