1. PHP / Говнокод #5478

    +158

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    $f=file('[путь к файлу]'); 
    shuffle($f); 
    $f[0] - первая случайная строка 
    $f[1] - вторая случайная строка 
    $f[2] - третья случайная строка

    вот PHP еще. если например несколько строк надо. ну и оптимальнее чем предложено выше.
    http://megaobzor.com/forum-top-77608.html

    Наверху было классическое

    $quote=file('words.txt'); 
    echo $quote[rand(0,count($quote)-1)];

    Несомненно, оптимальнее. Особенно, если строчек эдак тыщ сто.

    Кстати, предлагаю начать очередной холивар по поводу того, как с самыми меньшими затратами вынуть из файла рандомную строчку :)

    Запостил: 7ion, 02 Февраля 2011

    Комментарии (61) RSS

    • из файла. а из бд?
      Ответить
      • а из файла?
        Ответить
        • атавизм
          Ответить
          • обоснуйте
            Ответить
            • бд - структурированное хранилище с неплохим языком запросов.
              а файл - бинарная последовательность. за исключением сервисных функций вроде file_get_contents и file, вся работа низкоуровнева подобно Си - fopen,fgetc,fclose.
              В пхп даже нет такой привязки как в перле - хеши и dbm файлы
              Ответить
              • А что будет быстрее - подключение к БД и вытягивание из нее рандомной строки или открытие файла и чтение этой строки?
                Ответить
                • в первом случае подключение длительно, выборка быстра
                  во втором пробег файла длителен
                  Ответить
                  • а зачем это я буду бегать по файлу?
                    я могу поставить указатель в рандомное место и прочитать следующую за ним строчку.
                    Ответить
                    • не все строчки одинаково длинны
                      Ответить
                      • и что вы хотите этим сказать?
                        ftell() скажет мне длину файла.
                        изречения вряд ли будут длиннее 100 символов.
                        соответственно, если ftell()>100, то ftell()-100 даст мне положение указателя 99% не на последней строке.
                        дальше я беру и читаю строку fgets'ом, предварительно прогнав его вхолостую, чтоб он перешел на новую строку.
                        как итог - я не бегал по файлу, а к чему ваши слова я вообще не понимаю.
                        Ответить
                        • Но и случайность будет не случайна. Строка, у которой предшествующая строка будет в 20 символов будет встречаться гораздо реже, чем строка, у которой предыдущая с 100 символами.

                          Но ведь можно сначала файл преобразовать, чтобы строки были одинаковой длины, тогда ваш способ будет работать.
                          Ответить
          • Да, для домашней странички только из-за афоризмов мускуль и заводить.
            Ответить
            • ща даже халявные хостинги дают мускуль, че?
              Ответить
              • Вы из оравы тех, благодаря коду которых мощность техники неумолимо движется вперед?
                Ответить
                • я не из тех, кто использует свитчи вместо функций и весь код держит в одном файле, потому что "когда много файлов тормозит"
                  Ответить
                  • Довольно часто серьезные проекты перед сдачей склеивают в меньшее количество файлов ради экономии.
                    Ответить
                    • угу, какого размера должен быть проект? фейсбук?
                      Ответить
                      • любого, если в дальнейшем не предусматривается регулярное ковыряние в коде.
                        и то, можно хранить просто несклеенную копию, а пахать будет склеенная.
                        Ответить
                        • Зачем сжимать в один файл? Есть же APC, который кеширует опкод всех php-файлов, инклуд сотни файлов занимает от силы пару милисекунд, и при этом инклуд только нужных файлов пожирает меньше памяти чем инклуд всего, что на большом количестве запросов куда важнее чем та пара мили секунд.
                          Ответить
        • а из файла, смотря, по какому критерию нужно минимизировать - скорость или память
          Ответить
          • продемонстрируйте оба варианта, пожалуйста
            Ответить
            • нашел такой вариант:
              <?php
              function pc_randomint($max = 1) {
                $m = 1000000;
                return ((mt_rand(1,$m * $max)-1)/$m);
              }
              
              $line_number = 0;
              
              $fh = fopen('sayings.txt','r') or die($php_errormsg);
              while (! feof($fh)) {
                  if ($s = fgets($fh,1048576)) {
                      $line_number++;
                      if (pc_randomint($line_number) < 1) {
                          $line = $s;
                      }
                  }
              }
              fclose($fh) or die($php_errormsg);
              Ответить
              • Позвольте спросить - это вообще что?
                По-моему, этот код требует себе отдельную запись на этом сайте.
                Ответить
    • а зачем холиварить? просто не надо пользовать средства пхп для этого
      sed -n $((1 + $RANDOM % `wc -l file.txt`))p file.txt
      а еще лучше shuf -n 1 file.txt
      память у пхп больное место
      Ответить
      • в том-то и дело, задача усложняется тем, что код должен быть понимаем php-интерпретатором.
        это можно как-нибудь скормить консоли через похапе и получить ответ, затратив при этом меньше времени и средств, чем сам похапе?
        Ответить
        • а я о чем
          echo system('shuf -n 1 ' . $filename); // выводит одну рандомную строку
          если вдруг пакета не будет, можно попробовать вариант с sed
          оба шустрые
          но, как подсказывали парни, если скрипт соединяется с базой данных, то лучше залить данные в базу в виде "уникальный ключ - строка" и тянуть оттуда при помощи двух быстрых запросов, т.е. не использовать RAND() в запросе - он медленный, первым вынимать следующий ключ автоинкремента, рандомайзить на основе и выдергивать строку по рандомному ключу
          Ответить
          • я в консолях не розумею, а насчет ключей это да, в бд вообще всегда должен быть уникальный ид, иначе какая это база.
            и, да, насколько оно кроссплатформенно?
            echo system('shuf -n 1 file.txt'); под виндой под денвером мне ничего не вывело.
            Ответить
            • никсы только, но я не встречал ни одного здравомыслящего, кто бы разворачивал винду для проекта на пхп
              Ответить
              • а чо, красиво, сотни рахитектурного флейма, а потом внезапное признание, что целевая платформа - котер
                Ответить
    • > как с самыми меньшими затратами вынуть из файла рандомную строчку

      В любом случае придется считывать весь файл. Если, конечно, заранее не известно количество строк. А если известно, то процесс можно несколько ускорить. И память можно сэкономить.

      Вгляделся в код Люра, там как раз вроде что-то такое попытались сделать.
      Ответить
      • Допустим, нам известно кол-во строк.
        Что можно сделать?
        Мое предложение вообще делать вот так
        <?php
        //открываем файл для чтения
        $proxyfile=fopen (‘./proxies.txt’, ‘r’);
        
        //ставим указатель в конец файла
        fseek($proxyfile, 0, SEEK_END);
        
        // получаем размер файла (для файлов огромного размера filesize() может не работать)
        $len = ftell($proxyfile);
        
        // Генерим случайное число в диапазоне от нуля до размера файла (минус 20 добавлено, чтоб не попасть в самый конец файла)
        $posrand=mt_rand(0, $len)-20;
        
        // Перемещаем указатель в случайную позицию
        fseek($proxyfile, $posrand);
        
        // получаем строку, на которую мы попали указателем (строка может быть неполной, так как случайная позиция указателя может быть в любом месте строки)
        $line = fgets($proxyfile);
        
        // Возвращаем следующую строку, которая уже точно будет полной и применяем к ней trim()
        $proxy= trim(fgets($proxyfile));
        
        //закрываем файл
        fclose($proxyfile);
        ?>

        Насколько я знаю, здесь php нигде полностью файл не загрузит в память и размер файла не будет вообще играть роли.
        Но я могу ошибаться.
        Ответить
        • Это тоже неплохой говнокод ))
          И тут получается, чем длиннее строка, тем больше у нее шансов быть выбранной. Точнее не у нее, а у следующей за ней.

          Если известно количество строк, то можно тупо fgets-ом пролистывать до строки со случайным номером в диапазоне от нуля до общего количества строк.
          Ответить
          • да, это будет самый оптимальный вариант, я согласен.
            но давайте для наших рандомных фраз примем послабление - пусть они примерно одинаковой длины (+- 10 символов).
            тогда мой код гк не будет, а как раз-таки самым оптимальным.
            то есть для словаря, например, логинов или паролей мой код будет самым хорошим, чем листание fgets'ом, не так ли?
            Ответить
            • пользуй базу, не изобретай паровоз. век не тот на дворе
              Ответить
              • У меня есть словарь из ~100 вариантов паролей. Зачем мне ради этого база?
                Ответить
                • ну, вдруг вырастет ))
                  а если не вырастет, то
                  $quote=file('words.txt');
                  echo $quote[rand(0,count($quote)-1)];
                  самый оптимальный
                  Ответить
                  • но ведь file полностью грузит файл в память и еще делает массив из строк!
                    разве это не самый топорный метод?
                    Ответить
                    • зато сишка считает весь файл и разобьет его в массив быстрее, чем аналогичный код на пхп
                      Ответить
                • > Зачем мне ради этого база?
                  для дисциплины и упорядочения.
                  "зачем мне полочки и каталог для 10 книжек, я их лучше в углу покидаю"


                  проверочный код: 6666
                  Ответить
        • сдаётся, в любом случае необходим индекс.
          Ответить
          • Если файл постоянный, весьма годно будет сделать список "ссылок" на начало каждой строки. Тогда поиск вообще будет до ужаса туп и линеен.
            Ответить
            • Что вы имеете ввиду?
              Если файл имеет опредленное кол-во строк, то тогда, я думаю, хорошо будет просто рандомно прокручивать fgets до какой-либо строки.
              Ответить
              • Если eth0 имеет ввиду то, что я сейчас подумал - тогда прокручивать вообще ничего не нужно...
                Тогда можно сразу указывать какую строку вытаскивать.
                Как правило, так оно и есть. Файл, содержащий некий набор "крылатых" фраз, подвергается изменениям крайне редко.
                Так что есть смысл жёстко указать откуда именно следует расти ногам.
                Ответить
                • т.е. БД, состоящую из файла с данными и файла с индексом
                  осталось приделать педали...
                  Ответить
                  • БД... из двух файлов. На 5.25 дискете...
                    Или лучше на кассетах...
                    Тогда, действительно, "рандомно прокручивая магнитофоном"...
                    Ответить
                  • Иногда излишнее усложнение не принесёт ничего.
                    В моей практике был случай, когда рисовалась карта Москвы. Десяток миллионов точек в полигонах. Реляционная база данных довольно неплохо делала выборку для текущей области видимости, но расходы на IPC всё съедали. После перевода массива точек в файл появилась возможность значительно оптимизировать, поскольку не требовалось оптимальности. Прекеширование по районам, по соседним участкам, быстрый поиск - всё, что вообще нужно для комфортной работы.
                    Велосипед? Да, соглашусь. Но без него было бы нетривиально добиться вменяемой производительности.
                    Ответить
                • Так мне ж случайная строка нужна.
                  Допустим там 100 строк и мне нужна 53-я.
                  Я кручу fgets 52 раза, а с 53 считываю.
                  Других способов считать строку, не зная позицию первого символа, невозможно.
                  Ответить
                  • Либо первую строку использовать как индекс. Либо все строки одинаковой длины.
                    Ответить
                    • >Либо первую строку использовать как индекс
                      Как это?
                      И с изречениями, разумеется, второй способ не прокатит, если, конечно, их пробелами не дозабить.
                      Ответить
                      • fgets по-умолчанию 1 кб берёт, хватит для фразы?
                        --
                        В первой строчке хранить указатели на начала строк изречений.
                        --
                        Вообще-то, хотите быстрее - храните список в памяти, процесс под это дело запустите, модуль расширения под php,..
                        (главное назвать это навроде "mysql")
                        :)
                        Ответить
                  • Для этого индексы и нужны. Так мы будем знать начало каждой строки точно.
                    Второй вариант - выделение места под строку блоками определённого размера.
                    Ответить
        • > 7ion
          > Мое предложение вообще делать вот так...
          imho:
          Такой пример имеет право на существование в случае небольших нагрузок и объёма данных.
          Либо как предложил sectus - делать строки одинаковой длины, либо индексировать содержимое (по указателям начала строк) и fseek'ать уже по индексу.
          Либо изобретать новый велосипед - файловую систему...
          БД (те которые под php), на большие (огромные) объёмы данных тоже не ахти как расчитаны, у них индекс, всё же, свопится на диск, и в конечном счёте - опять же приходится упираться в возможности ФС.
          На мой взгляд - "кесарю - кесарево", возможности ресурсов должны оправдывать поставленные задачи.
          Ответить
          • да по данному вопросу вообще можно статьи писать, но еще важны и усилия на разработку.
            А то потом придет насяльника и скажет: что ты весь день хуйней страдал, тут работы на пять минут? И обьясняй ему, что ты выискивал оптимальный алгоритм считывания случайной фразы
            Ответить
            • Насяльникам результат нужен, а не алгоритмы. На то оне и насяльники.
              Ответить
              • вот вам и еще один способ образования говнокода: под давлением сверху
                Ответить
                • И по инициативе снизу.
                  Ответить
                • > образования говнокода
                  > под давлением сверху
                  Гастроэнтерология же ж.
                  Ответить
    • я предлагаю файл такой структуры:
      <?php //db.data.php:
      $data[]='aaaaa';
      $data[]='bbb';
      $data[]='cccccccccccc';

      и заполняется быстро, и включается одним include = ))))
      Ответить
    • компренда, выйди нахуй из сумрака = )
      Ответить

    Добавить комментарий