Assume you have a set of items in an array.
A, B, C, D, E, F, G, H
Using PHP, how would you randomly pair the letters together without pairing them with a duplicate of themselves?
Such as this:
A->pairedLetter = G
B->pairedLetter = C
C->pairedLetter = E
D->pairedLetter = A
E->pairedLetter = B
F->pairedLetter = D
G->pairedLetter = F
and so on...
EDIT: Oh, and also, If A is paired with F, F can NOT be paired with A. So there will have to be as many relationships as there are items.
Does it have to be perfectly random given your constraints? If you were willing to add in another constraint then you could make the problem very simple. If you were willing to make it so that the mappings all formed a single loop then you could just shuffle your array and then make element one pont at two, two point at three and the last element points at the first. You will guarantee that no element can poitn at itself (unless the array only has one element), no element will point at the element pointing at it (unless the array only has two elements) and that no element will be pointed at by more than one item.
You are restricting your results set slightly so losing a certain amount of the random element but if you are happy with this its extremely simpel to do.
This would print:
the way this works is it loops the values and deletes a value at the same time, so you always have 2 values at once but at the same time shrinking the array by 1.
then when we set the new keys were setting both of them to the new array, so the next time the loop iterates if the same value comes back around it just gets discarded :)
What about this ?
Output:
Works with even number of elements arrays as well as odd.
Update, using Chris' algorithm:
EDIT
following changes to the question
I've tried using a copy of the original array and using array_rand() but if it finds the same item as I'm iterating over, I have to run array_rand() again, which can fall into a endless loop.
I'm stumped, there has to be an elegant way to do this.
Duplicate the array. Call
shuffle
on one array. Then:array_pop
off an item from each array to form a pair.edit
With your extra condition, you'll need to check that every pair doesn't already exist. If it does (at the third stage) you can try taking different combinations (pop off first and third {pop off first, second, third and push second back on}) but you may still end up with an invalid pair at the end so would need to start again.