使用PHP,随机配对一组项,不与自身配对,也不直接配对
假设数组中有一组项 A、 B,C,D,E,F,G,H 使用PHP,您如何随机将字母配对在一起,而不将它们与它们自身的副本配对 例如:使用PHP,随机配对一组项,不与自身配对,也不直接配对,php,algorithm,random,Php,Algorithm,Random,假设数组中有一组项 A、 B,C,D,E,F,G,H 使用PHP,您如何随机将字母配对在一起,而不将它们与它们自身的副本配对 例如: A->pairedLetter = G B->pairedLetter = C C->pairedLetter = E D->pairedLetter = A E->pairedLetter = B F->pairedLetter = D G->pairedLetter = F 等等 编辑: 哦,还有,如果
A->pairedLetter = G
B->pairedLetter = C
C->pairedLetter = E
D->pairedLetter = A
E->pairedLetter = B
F->pairedLetter = D
G->pairedLetter = F
等等
编辑:
哦,还有,如果A和F配对,F就不能和A配对。
因此,关系的数量必须与项目的数量一样多。我曾尝试使用原始数组的副本并使用array_rand(),但如果它找到与我迭代的项目相同的项目,我必须再次运行array_rand(),这可能会陷入一个无休止的循环 我被难住了,必须有一种优雅的方法来实现这一点。复制阵列。 在一个数组上调用
shuffle
。
然后:
array\u pop
从每个数组中取出一个项目,形成一对$arrayValues = range('A','H');
shuffle($arrayValues);
while (count($arrayValues) > 0) {
echo array_pop($arrayValues),' is matched with ',array_pop($arrayValues),'<br />';
}
洗牌($arrayValues);
而(计数($ArrayValue)>0){
echo array_pop($arrayValues),'与',array_pop($arrayValues),'匹配; } 编辑 以下是对问题的修改:
$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 />';
}
$arrayValues=范围('A','H');
$tmpArrayValues=$arrayValues;
$pairs=array();
洗牌($tmpArrayValues);
foreach($arrayValue作为$arrayValue){
$tmpValue=array\u pop($tmpArrayValues);
而($arrayValue==$tmpValue)| |((isset($pairs[$tmpValue]))和($pairs[$tmpValue]==$arrayValue))){
数组_unshift($tmpArrayValues,$tmpValue);
$tmpValue=array\u pop($tmpArrayValues);
}
$pairs[$arrayValue]=$tmpValue;
}
foreach($key=>$value){
echo$key'与“,$value”匹配,
;
}
这将打印:
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"
}
其工作方式是它循环值并同时删除一个值,因此总是同时有2个值,但同时将数组缩小1
然后,当我们设置新的键时,我们将它们都设置为新数组,因此下次循环迭代时,如果相同的值返回,它就会被丢弃:)这是怎么回事
// 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);
输出:
Array
(
[A] => B
[B] => F
[F] => E
[E] => D
[D] => C
[C] => A
)
适用于偶数个元素数组和奇数个元素数组
使用Chris算法更新:
$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];
$arr=array('A','B','C','D','E','F');
洗牌($arr);
$res=array();
对于($i=0;$i在给定约束的情况下,它必须是完全随机的吗?如果你愿意添加另一个约束,那么你可以使问题变得非常简单。如果你愿意使映射都形成一个循环,那么你可以洗牌你的数组,然后使元素二点一桥,三点二点和last元素指向第一个元素。您将保证没有元素可以指向自身(除非数组只有一个元素),没有元素会指向指向它的元素(除非数组只有两个元素),并且没有元素会被多个项指向
您稍微限制了结果集,因此丢失了一定数量的随机元素,但如果您对此感到满意,则非常简单。在数组上使用shuffle函数并检查映射是否有效(a不映射到a,如果a映射到B,则B不映射到a)。以下操作应满足您的要求:
$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);
$values=array('A','B','C','D','E','F','G');
$new_values=数组('A','B','C','D','E','F','G');
$random=shuffle($new_值);
//随机洗牌第二个数组的顺序
$mappings=array();
$validMappings=false;
//继续重试其他映射,直到找到有效结果
while(!$validMappings){
//设置从$values到$new_值的映射
对于($i=0;$i$value的映射){
如果($mappings[$key]==$mappings[$value]){
$validMappings=false;
打破
}
}
//如果为false,则重新排列新值并再次测试
如果(!$validMappings){
$random=shuffle($new_值);
}
}
打印(映射);
除非您在回答自己的问题(鼓励您这样做),否则不要在自己的问题中添加答案。编辑您的问题。这不是答案,它应该添加为您问题的注释,或者您的问题应该使用此新信息进行编辑。此外,除非您有一个严重损坏的随机数生成器,否则您不会以这种方式进入无限循环。请仔细想想。它必须只返回您正在尝试匹配以使其发生。相信我,我已经仔细考虑过了。有时只有两个或三个可能的返回值。我将添加注释,感谢指针。只要只有一个返回值不是您要匹配的字母,这就不会是一个无限循环。我不是说这是最好的方法,但值得一提。谢谢,我会试试。我想调用array_rand()还是shuffle()?洗牌,抱歉。答案已修改。我对问题添加了一些编辑,我认为您的解决方案无法通过这些编辑解决问题。这样做有效吗?如果除了两个数组中的最后一个项目相同之外,一切都正常会怎么样?@Damien因此第一个要点:array\u pop
取自结尾。我刚刚编辑了我的问题,以包括
$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);