Using PHP, arbitrarily join a group of elements without linking them to yourself, without direct pairs

Suppose you have a set of elements in an array.

A, B, C, D, E, F, G, H

Using PHP, how would you accidentally put letters together without associating them with a duplicate of yourself?

For example:

A->pairedLetter = G B->pairedLetter = C C->pairedLetter = E D->pairedLetter = A E->pairedLetter = B F->pairedLetter = D G->pairedLetter = F 

etc.

EDIT: Oh, and also, if A is conjugated to F, F cannot be conjugated to A. So there should be as many relationships as there are.

+2
source share
7 answers

How about this?

 // input array $arr = array('A','B','C','D','E','F'); // result array $res = array(); // get first element and save it $first = $ele1 = array_shift($arr); while(count($arr)) { // get random element $ele2 = array_rand($arr); // associate elements $res[$ele1] = $arr[$ele2]; // random element becomes next element $ele1 = $arr[$ele2]; // delete the random element array_splice($arr, $ele2, 1); } // associate last element woth the first one $res[$ele1] = $first; print_r($res); 

Output:

 Array ( [A] => B [B] => F [F] => E [E] => D [D] => C [C] => A ) 

It works with an even number of element arrays, as well as odd.

Update using Chris algorithm:

 $arr = array('A','B','C','D','E','F'); shuffle($arr); $res=array(); for($i=0;$i<count($arr);$i++) { $res[$arr[$i]] = $arr[$i+1]; } $res[$arr[count($arr)-1]] = $arr[0]; 
+3
source

Duplicate the array. Call shuffle for one array. Then:

  • Make sure that the first elements are different (if they switch the first two elements of the same array).
  • array_pop from the element from each array to form a pair.
  • If the elements are the same, pop two from one array and pair up, then two from the other.

change

With the additional condition, you will need to verify that each pair does not yet exist. If this happens (in the third stage), you can try using different combinations (jump from the first and third {pop off first, second, third and push second back on}), but you can still end up with an invalid pair in end so that you will need to start again.

+3
source

Do I need to be completely random given your limitations? If you wanted to add another restriction, you could make the problem very simple. If you wanted to make it so that all the mappings form one cycle, you could just shuffle your array, and then make one pont element in two, two points in three, and the last element on the first. You guarantee that no element can poitn itself (unless the array has only one element), no element will point to an element pointing to it (if only the array has only two elements), and that no element will more than one item

You limit your results to a multitude in order to lose a certain amount of a random element, but if you are happy with this extremely simpal to do.

+3
source
 $array = array( 'A','B','C', 'D','E','F', 'G','H','I','J' ); $new = array(); if(count($array) % 2 != 0) { array_pop($array); // Got to remove 1 element to make them even. } foreach($array as $item) { $_t = array_pop($array); //Key if(!isset($new[$item])) { $new[$item] = $_t; $new[$_t] = $item; } } var_dump($new); 

This will print:

 array(10){ ["A"]=> string(1) "J" ["J"]=> string(1) "A" ["B"]=> string(1) "I" ["I"]=> string(1) "B" ["C"]=> string(1) "H" ["H"]=> string(1) "C" ["D"]=> string(1) "G" ["G"]=> string(1) "D" ["E"]=> string(1) "F" ["F"]=> string(1) "E" } 

how it works, it cyclically changes the values ​​and at the same time deletes the value, so you always have 2 values ​​at the same time, but at the same time it reduces the array by 1.

then when we install new keys, they install both of them into a new array, so the next time the loop repeats, if the same value is returned, it is simply discarded :)

+1
source

I tried to use a copy of the original array and use array_rand (), but if it finds the same element as the iteration, I need to run array_rand () again, which may end up in an infinite loop.

I'm at a dead end, there must be an elegant way to do this.

0
source
 $arrayValues = range('A','H'); shuffle($arrayValues); while (count($arrayValues) > 0) { echo array_pop($arrayValues),' is matched with ',array_pop($arrayValues),'<br />'; } 

EDIT

following changes to the question

 $arrayValues = range('A','H'); $tmpArrayValues = $arrayValues; $pairs = array(); shuffle($tmpArrayValues); foreach($arrayValues as $arrayValue) { $tmpValue = array_pop($tmpArrayValues); while (($arrayValue == $tmpValue) || ((isset($pairs[$tmpValue])) && ($pairs[$tmpValue] == $arrayValue))) { array_unshift($tmpArrayValues,$tmpValue); $tmpValue = array_pop($tmpArrayValues); } $pairs[$arrayValue] = $tmpValue; } foreach($pairs as $key => $value) { echo $key,' is matched with ',$value,'<br />'; } 
0
source

Using the shuffle function in the array and validating the mappings (A does not map to A and that if A maps to B, then B does not map to A). The following should do what you want:

 $values = array('A','B','C','D','E','F','G'); $new_values = array('A','B','C','D','E','F','G'); $random = shuffle($new_values); //randomly shuffle the order of the second array $mappings = array(); $validMappings = false; //continue to retry alternative mappings until a valid result is found while(!$validMappings) { //set the mappings from $values to $new_values for($i = 0; $i < count($values); $i++) { $mappings[$values[$i]] = $new_values[$i]; } $validMappings = true; //check validity of the current mapping foreach ($mappings as $key=>$value) { if($mappings[$key] == $mappings[$value]) { $validMappings = false; break; } } //if false shuffle the new values and test again if(!$validMappings) { $random = shuffle($new_values); } } print_r($mappings); 
0
source

All Articles