php - 随机生成器返回无限重复

标签 php

我正在尝试创建一个随机字符串,用作短引用号。在过去的几天里,我一直在努力让它发挥作用,但它似乎达到了大约 32766 条记录,然后它继续无休止地重复。我至少需要 200,000 个变体。

下面的代码是一个非常简单的模型,用于解释会发生什么。代码的语法应根据 1a-x1y2z(示例)给出比 32k 更多的结果

我感觉这可能与内存有关但不确定。有什么想法吗?

<?php

function createReference() {
    $num = rand(1, 9);
    $alpha = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz"), 0, 1);
    $char = '0123456789abcdefghijklmnopqrstuvwxyz';
    $charLength = strlen($char);
    $rand = '';
    for ($i = 0; $i < 6; $i++) {
        $rand .= $char[rand(0, $charLength - 1)];
    }
    return $num . $alpha . "-" . $rand;
}

$codes = [];
for ($i = 1; $i <= 200000; $i++) {
    $code = createReference();
    while (in_array($code, $codes) == true) {
        echo 'Duplicate: ' . $code . '<br />';
        $code = createReference();
    }
    $codes[] = $code;
    echo $i . ": " . $code . "<br />";
}
exit;
?>

更新

所以我开始怀疑这是否与我们的 WAMP 设置 (Bitnami) 不符,因为我们的本地机器在开始复制之前正好达到 1024 条记录。通过从上面的字符串中删除 1 个字符(而不是 for 循环中的 6 个字符,我将其设为 5),它正好达到 32768 条记录。

我把脚本上传到我们的centos服务器,没有重复。

在我们的环境中,什么会导致这种行为?

最佳答案

代码在我看来过于复杂。让我们暂时假设您真的想创建 n 个独特的字符串,每个字符串都基于单个随机值(rand/mt_rand/介于 INT_MIN、INT_MAX 之间的某个值)。

您可以首先将随机值的生成与编码解耦(代码中似乎没有任何内容使字符串依赖于任何先前的状态——唯一性除外)。比较整数比比较任意字符串快很多。
mt_rand() 返回 INT_MIN 和 INT_MAX 之间的任何值,使用 32 位整数(也可以是 64 位,取决于 php 的编译方式),给出 ~232 元素。您想选择 200k,让我们将其设为 400k,即值范围的 1/10000。因此,可以合理地假设一切都与唯一性相得益彰……然后稍后再检查。并在发生碰撞时添加更多值。同样比在循环的每次迭代中检查 in_array 快得多。
一旦你有足够的值,你就可以将它们编码/转换成你想要的格式。我不知道 <digit><character>-<something> 是否格式是强制性的,但假设它不是 -> base_convert()

<?php
function unqiueRandomValues($n) {
    $values = array();
    while( count($values) < $n ) {
        for($i=count($values);$i<$n; $i++) {
            $values[] = mt_rand();
        }
        $values = array_unique($values);
    }
    return $values;
}

function createReferences($n) {
    return array_map(
        function($e) {
            return base_convert($e, 10, 36);
        },
        unqiueRandomValues($n)
    );
}

$start = microtime(true);
$references = createReferences(400000);
$end = microtime(true);
echo count($references), ' ', count(array_unique($references)), ' ', $end-$start, ' ', $references[0];

打印例如400000 400000 3.3981630802155 f3plox在我的 i7-4770 上。 ($end-$start部分一直在3.2和3.4之间)

使用 base_convert() 可以是像 li10 这样的字符串,如果您必须手动输入字符串,那么破译起来会很烦人。

关于php - 随机生成器返回无限重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35795891/

相关文章:

PHP 7 simpleXML fatal error

php - 如何创建包含时自动生成代码的 Composer 库包

php - 如何在 PHP 代码中正确设置错误报告?

php - 组合数组

javascript - 检查前一行值并相应地显示下一行

php - UTF-8贯穿始终

php - 有没有适合初学者的 Solr 教程?

php - 如何告诉 Paris/ORM 哪个表用于模型?

PHP : send mail in localhost

php from 向 mysql 数据库表插入一行