如何从排除一个值的数组中随机选择?

时间:2015-10-19 06:37:06

标签: php arrays

随着假期慢慢接近,是时候再次摘下吸管了。我们总是从一个装有大家名字的盒子里挑一张纸。但是,今年我想解决使用PHP从框中选择自己名字的问题。

我有一个名为ex:

的数组
$names = [
    'John',
    'Jane',
    'Joe',
    'Matt',
    'Steve',
    'Anne',
    'Karin'
];

对于这些名字中的每一个,我想选择4个随机名称,以便最后每个人都有4个名字,他们必须为此购买礼物。

问题

好吧,我被卡住了。我已经想到了如何做到这一点的百万种方法,但我无法想出任何东西。

到目前为止我尝试了什么

  • 使用foreach
  • 使用array_rand()
  • 转移阵列

这些的问题在于,一个人不应该选择自己的名字,并且每个人都应该被选中次数(4)。

更新

已经发布了一些很棒的答案。我不确定这对每个人来说是否公平。最后每个人都应该从4个不同的人那里得到4份礼物。

我在考虑将每个名称添加到$names数组4次,然后应用您的一个答案。我是否在正确的轨道上?

更新2

我现在尝试过的事情:

function select_rand($array, $exclude_array) {
    $diff = array_diff($array, $exclude_array);
    return $diff[array_rand($diff, 1)];
}

$workArray = [
    '0' => $names,
    '1' => $names,
    '2' => $names,
    '3' => $names,
];

foreach ($names as $k => $name) {
    $i = 0;
    $new[$name] = array();
    while ($i < 4) {
        $value = select_rand($workArray[$i], array_merge($new[$name], array($name)));
        if (($key = array_search($value, $workArray[$i])) !== false) {
            unset($workArray[$i][$key]);
        }
        $new[$name][] = $value;
        $i++;
    }
}

这仅适用于少数几个。

4 个答案:

答案 0 :(得分:3)

我会使用shuffle和array_slice来完成这项工作:

$names = [
    'John',
    'Jane',
    'Joe',
    'Matt',
    'Steve',
    'Anne',
    'Karin'
];

foreach ($names as $name) {
   // working array
   $working = $names;
   // remove current name from array,no one wants to buy presents for him/her self..
   unset($working[$name]);
   shuffle($working);
   $people = array_slice($working, 0, 4);
   echo $name . ' has to buy presents for:';
   var_dump($people);
}

答案 1 :(得分:1)

这可以提供帮助 -

function select_rand($array, $exclude_array) {
    $diff= array_diff($array, $exclude_array);
    return $diff[array_rand($diff, 1)];
}

$names = array(
    'John',
    'Jane',
    'Joe',
    'Matt',
    'Steve',
    'Anne',
    'Karin'
);
foreach($names as $name)
{
    $i = 0;
    $new[$name] = array();
    while($i < 4) {
        $new[$name][] = select_rand($names, array_merge($new[$name], array($name)));
        $i++;
    }
}

这将为包含 4个唯一名称的数组中的每个arrayname)生成新的key

FIDDLE

<强>更新

$new[$name][] = select_rand($names, array_merge($new[$name], array($name, 'Karin')));

答案 2 :(得分:1)

您可以像

一样创建自定义功能
$names = [
    'John',
    'Jane',
    'Joe',
    'Matt',
    'Steve',
    'Anne',
    'Karin'
];

$my_name = "John";
$limit = 4;

function get_name($arr,$your_name,$limit){
    $key = array_flip($arr)[$your_name];
    unset($arr[$key]);
    $rand_keys = array_rand($arr,$limit);
    $result = array_intersect_key($arr, array_flip($rand_keys));
    return implode(',',$result);
}

echo get_name($names,$my_name,$limit);

Demo

答案 3 :(得分:1)

我认为如果你想每人均匀分配礼物,你需要对它有更多的控制权。无论如何,在这段代码中我记录了每个人的礼物数量。我用零初始化它:$presents = array_fill_keys($names, 0);。然后在每次选择后我更新了这个数字$presents[$key]++;

<?php
$names = array(
    'John',
    'Jane',
    'Joe',
    'Matt',
    'Steve',
    'Anne',
    'Karin'
);

$presents_number = 4;
// initialization 
$presents = array_fill_keys($names, 0);
$names_names = array();
foreach ($names as $i => $picker)  {
    $box = $names;
    unset($box[$i]);

    // filter out the people with maximum presents:
    foreach ($presents as $key => $number) {
        if (($presents[$key] > $presents_number-1) && in_array($key, $box)) {
            $box = array_diff($box, array($key));
        }
    }

    // shuffle the box and select 4 top
    shuffle($box);
    $selection = array_slice($box, 0, $presents_number);
    foreach ($selection as $key) {
        $presents[$key]++;
    }
    $names_names[$picker] = $selection;
}

echo "<pre>";
print_r($names_names);
echo "</pre>";

在数学上可以考虑更多。特别是因为循环可能发生,这个算法可能会出错。我没有时间花在它上面。但作为每人3人和一人的例子。 (A,B,C)

正确答案:

  

A =&gt; {B}

     

B =&gt; {C}

     

C =&gt; {A}

错误答案:

  

A =&gt; {B}

     

B =&gt; {A}

     

C =&gt; {}

基本上,完美的算法应该避免这些错误的答案。也许以后我把问题修改为这篇文章的更新。