Получить случайное слово определенной длины из списка слов

Я пишу простую функцию PHP, которая будет обращаться к word-list.txt и извлекать случайное слово (слова разделены новой строкой). Это слово должно иметь максимальную длину $maxlength. В том виде, как я это написал, он будет вытягивать слово, и если длина слишком велика, он будет продолжать получать новое слово, пока оно не станет меньше или равно $maxlength. Проблема, с которой я сталкиваюсь, заключается в том, что скрипт возвращает фатальную ошибку для максимального времени выполнения. Вот код:

function GetWord($maxlength) {
    $file_content = file('word-list.txt');
    $nword = $file_content[array_rand($file_content)];

    while(mb_strlen($nword) > $maxlength) {
        $nword = $file_content[array_rand($file_content)];
    }

    return $nword;
}

Единственная альтернатива, о которой я мог подумать, - это поместить список слов в базу данных и иметь столбец с длиной каждого соответствующего слова. Это позволило бы мне выбирать варианты слов в зависимости от их длины. Однако я пытаюсь избежать использования базы данных, поэтому я хочу выяснить, что не так с моим скриптом. Любая помощь приветствуется. Спасибо!


person bigbluehouse    schedule 20.01.2017    source источник
comment
Я должен был упомянуть, что этот файл довольно большой и содержит более 9000 строк. Это приводит к тому, что некоторые из данных предложений по-прежнему истекают.   -  person bigbluehouse    schedule 21.01.2017


Ответы (3)


Следующий класс выполняет некоторую сортировку при создании экземпляра, но тогда каждый поиск случайного слова занимает всего O(1) времени:

class RandomWord {
    private $words;
    private $boundaries;

    private static function sort($a, $b){
        return strlen($a) - strlen($b);
    }

    function __construct($file_name) {
        $this->words = file($file_name, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

        // Sort the words by their lenghts
        usort($this->words, array('RandomWord', 'sort'));

        // Mark the length boundaries
        $last = strlen($this->words[0]);

        foreach($this->words as $key => $word) {
            $length = strlen($word);

            if ($length > $last) {
                for($i = $last; $i < $length; $i++) {
                    // In case the lengths are not continuous
                    //    we need to mark the intermediate values as well
                    $this->boundaries[$i] = $key - 1;
                }
                $last = $length;
            }
        }
    }

    public function get($max_length) {
        if (isset($this->boundaries[$max_length])) {
            return $this->words[rand(0, $this->boundaries[$max_length])];
        }

        return $this->words[array_rand($this->words)];
    }
}

Используйте это как:

$r = new RandomWord("word-list.txt");
$word1 = $r->get(6);
$word2 = $r->get(3);
$word3 = $r->get(7);
...

Обновление: теперь я проверил это и работает.

person Crouching Kitten    schedule 20.01.2017

Я думаю, что проблема возникает из-за чрезмерного усложнения вещей.

Вы можете взорвать содержимое

$content_array = explode("\n", $file_content);

Перетасовать массив

shuffle($content_array)

А затем найдите первое слово заданной длины.

foreach($content_array as $word) {
    if(strlen($word) == $word_length)
        return $word;
}

Я бы лично поместил все в базу данных.

person Bryant Jackson    schedule 20.01.2017

Повторная попытка со случайными индексами действительно довольно неэффективна.

Вы можете отфильтровать строки по условию длины, чтобы у вас остались только допустимые строки, а затем перевернуть эти строки, чтобы они стали ключами. Затем array_rand можно использовать для выбора случайного ключа из них. Все это можно сделать с помощью функционального программирования:

function GetWord($maxlength) {
    return array_rand(array_flip(array_filter(file('word-list.txt'), 
        function($line) use ($maxlength) {
            return mb_strlen($line) <= $maxlength;
        })));
}
person trincot    schedule 20.01.2017