我怎样才能逐渐使阵列更稀疏?

时间:2012-05-29 13:50:25

标签: php language-agnostic

我有一个完全填充的值数组,我想随意删除此数组中的元素,并向远端移除更多元素。

例如,给定输入(其中a。表示填充的索引)

............................................

我想要像

这样的东西
....... . ...  .. .  .  ..    .          .  

我的第一个想法是计算元素,然后遍历数组,在当前索引和数组总大小之间的某处生成一个随机数,例如:

if ( mt_rand( 0, $total ) > $total - $current_index ) 
    //remove this element

然而,因为这需要在循环每次循环时产生一个随机数,所以它变得非常艰巨。

有更好的方法吗?

3 个答案:

答案 0 :(得分:2)

一种简单的方法是为每个条目翻转加权硬币,硬币翻转更加加权到最后。例如,如果数组的大小为n,则对于每个条目,您可以选择从0n-1的随机数,并且只有在索引小于或等于随机数时才保留该值。 (也就是说,保持每个条目的概率1 - index/total。)这有一个很好的优势,如果你打算压缩你的数组,你正在使用一个足够好但有效的随机数发生器(可能是对一个nonce的简单整数哈希),它对内存访问来说会相当快。

另一方面,如果您只是消除了一些项目并且没有重新排列数组,那么您可以使用某种加权随机数生成器,它通常会选择朝向索引末尾的数字。例如,如果你有一个随机数生成器,它生成值为[0,1]的浮点数(闭合或开放边界无关紧要),可以考虑获得这样一个随机浮点r并将其平方。这往往更喜欢较低的价值。你可以通过翻转来解决这个问题:1-r^2。当然,您需要将其设置在0n - 1的索引范围内,因此请floor(n * (1 - r^2))并将n向下舍入到n-1

这两种技术实际上存在无限多种变化。

答案 1 :(得分:2)

这可能不是最好/最有效的方法,但这是我能提出的最好的it does work

N.B。键盘示例需要很长时间才能执行,但这是因为我添加到最后的漂亮打印循环,所以你可以看到它明显有效。如果删除内部循环,执行时间将降至可接受的水平。

<?php

  $array = range(0, 99);

  for ($i = 0, $count = count($array); $i < $count; $i++) {

    // Get array keys
    $keys = array_keys($array);

    // Get a random number between 0 and count($keys) - 1
    $rand = mt_rand(0, count($keys) - 1);

    // Cut $rand elements off the beginning of the keys
    $keys = array_slice($keys, $rand);

    // Unset a random key from the remaining keys
    unset($array[$keys[array_rand($keys)]]);

  }

答案 2 :(得分:1)

此方法不是随机的 - 它可以通过定义函数及其反函数来实现。具有不同常系数的不同函数将具有不同的分布特征。

结果非常像模式,就像将连续函数映射到像数组这样的离散结构时所期望的那样。

这是使用二次函数的示例。你可以尝试改变常数。

演示:http://codepad.org/ojU3s9xM

#as in y = x^2 / 7;
function y($x) {
    return $x * $x / 7;
}
function x($y) {
    return 7 * sqrt($y);
}

$theArray = range(0,100);
$size = count($theArray);

//use func inverse to find the max value we can input to $y() without going out of array bounds
$maximumX = x($size);
for ($i=0; $i<$maximumX; $i++) {
    $index = (int) y($i);

    //unset the index if it still exists, else, the next greatest index
    while (!isset($theArray[$index]) && $index < $size) {
        $index++;
    }

    unset($theArray[$index]);
}




for ($i=0; $i<$size; $i++) {
    printf("[%-3s]", isset($theArray[$i]) ? $theArray[$i] : '');
}
相关问题