Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用PHP,随机配对一组项,不与自身配对,也不直接配对_Php_Algorithm_Random - Fatal编程技术网

使用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、 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和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);