С Новым годом! Форум программистов, компьютерный форум, киберфорум
PHP для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.88/25: Рейтинг темы: голосов - 25, средняя оценка - 4.88
0 / 0 / 0
Регистрация: 30.05.2011
Сообщений: 16

Случайный выбор уникальных строк из файла без занесения последнего в массив

24.02.2016, 18:58. Показов 4888. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую!

К сожалению, использование больших массивов - это лишняя трата ОЗУ. Как я понимаю, взяв в такой массив файл размером 25 МБ, PHP зарезервирует под него все 50. А если файл ещё больше? В общем, хотелось бы работать с такими файлами напрямую, т.е. без предварительного занесения их в массивы. Базы данных не рассматриваю

Вот код, который берёт 9 случайных строк из файла и выводит их на экран:
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Подсчитываем кол-во строк в файле.
$f = fopen('anydata.txt', "r");
    $counter = 0;
    while (fgets($f)) {
        $counter++;
    }
fclose($f);
 
# Выбираем 9 случайных строк из файла с попутным выводом их на экран.
$num = 9;
for ($i = 0; $i < $num; $i++) {
    $n = 0;
    $random = mt_rand(0, $counter - 1);
    $f = fopen('anydata.txt', "r");
        while ($n <= $random) {
            $buffer = fgets($f);
            $n++;
        }
        echo "$random : $buffer<br />"; # номер_строки : сама_строка
    fclose($f);
}
Код работает прекрасно, памяти не жрёт вообще, но в нём не учитываются возможные повторы случайных строк! Как нужно изменить этот алгоритм, чтобы использовались только уникальные строки?

Единственное, что приходит в голову - это создание массива, кол-во ключей которого равно кол-ву строк в файле. Все значения в этом массиве, разумеется, равны 0 (для экономии ОЗУ). Но если убрать из такого массива очередной элемент, после чего отсортировав его, это никак не скажется на строках самого файла. Далее, лезут мысли типа зацикливания mt_rand до тех пор, пока очередная взятая строка не будет уникальной среди уже взятых ранее, но это реально бред, а если нужно взять 900 тыс. уникальных строк из 1 млн.?

Добавлено через 15 минут
Забыл отметить: все строки в файле уникальные сами по себе.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
24.02.2016, 18:58
Ответы с готовыми решениями:

Подскажите, как сделать случайный выбор и случайный выбор ответов?
подскажите как сделать случайный выбор вопросов и случайны выбор ответов var questions = , , , , , , ,

Подсчет количества уникальных строк и числа строк с каждым из уникальных значений
Здравствуйте, есть таблица с текстовой колонкой. Нужно получить количество строк, в которых значение этой колонки уникально и число строк...

Случайный выбор строки из файла
Доброго времени суток. Вот такая задачка есть ТХТ файл в нем по срокам расписаны вопросы : 1 строка : Ваше имя ? 2 строка: Ваш...

9
 Аватар для alexsamos33
669 / 640 / 335
Регистрация: 26.04.2014
Сообщений: 2,122
24.02.2016, 19:44
sMario, Может быть вам подойдёт функция array_unique?
0
1943 / 1768 / 825
Регистрация: 23.01.2014
Сообщений: 6,230
24.02.2016, 19:47
Цитата Сообщение от sMario Посмотреть сообщение
для экономии ОЗУ
А Вы уверены в рациональности? Что это за машина такая, для которой 50 МБ ОЗУ жалко, но при этом процессорного времени не жалко? Зачем Вы так сильно будете нагружать машину?

Тем более этот скрипт что, будет работать как демон? Или все-таки он будет запускаться, выполняться, и тут же прекращаться? Тогда в этом точно нет смысла.
0
Hello Kitty
 Аватар для WhiteMind
690 / 562 / 402
Регистрация: 12.02.2016
Сообщений: 1,436
Записей в блоге: 1
24.02.2016, 19:58
Лучший ответ Сообщение было отмечено sMario как решение

Решение

Цитата Сообщение от sMario Посмотреть сообщение
это лишняя трата ОЗУ

впрочем это легко сделать и по вашему условию
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
# Подсчитываем кол-во строк в файле.
 
function FileGetCount( $path ) {
    if ( $f = fopen( $path , "r" ) ) {
        $counter = 0;
        while (fgets($f)) { $counter++; }
        fclose($f);
        return $counter;
    }
    return false;
}
function GetRandomArray( $num , $lineCount ) {
    if ( $num > $lineCount ) {
        $num = $lineCount;
    }
 
    $subFunction = function( &$result , &$num , $min , $max ) use(&$subFunction) {
        if ( ( $num <= 0 ) || ( $min > $max ) ) {
            return [];
        }
        $key = mt_rand( $min , $max );
        $result[] = $key;
        $num--;
        if ( mt_rand(0,1) ) {
            $subFunction( $result , $num , $min , $key-1 );
            $subFunction( $result , $num , $key+1 , $max );
        } else {
            $subFunction( $result , $num , $key+1 , $max );
            $subFunction( $result , $num , $min , $key-1 );         
        }
    };
    $result = [];
    $subFunction( $result , $num , 0 , $lineCount - 1 );
    return $result;
}
function EchoRandomLine( $path , $randomMap ) {
    if ( $f = fopen( $path , "r" ) ) {
        $last = 0;
        foreach($randomMap as $line) {
            rewind($f);
            $newLine = $line = $line+1;
            while($newLine--) {
                $buffer = fgets($f);
            }
            echo "$line : $buffer<br />"; # номер_строки : сама_строка
        }
        fclose($f);
        return true;
    }
    return false;
}
 
$path = "line-test.txt";
$countRandomLine = 9;
 
$countLine = FileGetCount( $path );
$randomMap = GetRandomArray( $countRandomLine , $countLine );
EchoRandomLine( $path , $randomMap );
возможно для скорости вариант
PHP
1
2
3
4
5
6
7
8
        foreach($randomMap as $line) {
            rewind($f);
            $newLine = $line = $line+1;
            while($newLine--) {
                $buffer = fgets($f);
            }
            echo "$line : $buffer<br />"; # номер_строки : сама_строка
        }
не самый лучший, но озу будет в порядке
2
0 / 0 / 0
Регистрация: 30.05.2011
Сообщений: 16
24.02.2016, 20:25  [ТС]
Цитата Сообщение от pav1uxa Посмотреть сообщение
А Вы уверены в рациональности? Что это за машина такая, для которой 50 МБ ОЗУ жалко, но при этом процессорного времени не жалко? Зачем Вы так сильно будете нагружать машину?
Для одного запроса - не проблема, конечно. А если таких запросов одновременно много? А если помимо этого, на хостинге есть и другие сработавшие скрипты? Так и набежит. А что касается процессорного времени, то судя по microtime() разница между непосредственной работой с файлом и прогоном этого файла через массив в вышеобозначенной задаче минимальна, сотые секунды. По крайней мере на файле с 10 тыс. строк. Но во втором случае ещё и ОЗУ минусуется в два размера занесённого в массив файла. К тому же, unset(массив) освобождает память только частично, что тоже на доли секунды подливает масла в огонь.

Может я конечно чего-то не понимаю, но мне всё это видится именно в таком ключе Поправьте, если не согласны.

Цитата Сообщение от pav1uxa Посмотреть сообщение
Тем более этот скрипт что, будет работать как демон? Или все-таки он будет запускаться, выполняться, и тут же прекращаться? Тогда в этом точно нет смысла.
Нет, не демон, но кол-во одновременных запусков может быть большим и пересекаться с другими работающими скриптами, см. выше.

Цитата Сообщение от WhiteMind Посмотреть сообщение
впрочем это легко сделать и по вашему условию
Спасибо, изучаю
0
1943 / 1768 / 825
Регистрация: 23.01.2014
Сообщений: 6,230
24.02.2016, 20:48
Цитата Сообщение от sMario Посмотреть сообщение
А что касается процессорного времени, то судя по microtime() разница между непосредственной работой с файлом и прогоном этого файла через массив в вышеобозначенной задаче минимальна, сотые секунды.
Вот это Ваше предложение оно как бы говорит в мою пользу, понимаете?

Занять 50 мегабайт ОЗУ на 100 мс это вообще незаметно произойдет. А вот как именно будет это происходить - это другой вопрос.

Выделить 50 МБ ОЗУ и освободить их через 100 мс - это вообще фигня. А Вы те же самые 50 МБ прогоняете, только не за 1 раз, а за 1000000 (или сколько там у Вас строк в этих 50 МБайтах). Да и в итоге Вы этот файл 2 раза прогоняете, судя по скрипту. Вот такими манипуляциями действительно можно процессор подгрузить, это увеличит время исполнения.

Ну я не знаю как еще понятнее объяснить. Представьте, что Вам сложнее, 1 раз поднять 10 килограмм и тут же бросить, или 10000 раз поднять по 1 грамму? Тут то же самое.

Добавлено через 1 минуту
Цитата Сообщение от WhiteMind Посмотреть сообщение
PHP
1
2
3
4
5
6
7
8
9
function FileGetCount( $path ) {
* * if ( $f = fopen( $path , "r" ) ) {
* * * * $counter = 0;
* * * * while (fgets($f)) { $counter++; }
* * * * fclose($f);
* * * * return $counter;
* * }
* * return false;
}
заменяется
PHP
1
count(file("file.txt"));
Добавлено через 6 минут
Да и вообще все функции с работой с файлами следует сводить к минимуму. Не нужно файл 2 раза перечитывать. Я бы начал так
PHP
1
2
3
4
5
6
7
8
9
10
11
// Считываем все строки в массив,
// исключая пустые строки и переносы строк
$file = file("text.txt", FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES);
 
// Количество полученных строк
$cnt = count($file);
 
// Осталось создать массив $numbers с нужным количеством
// рандомных цифр в диапазоне [0, $cnt) и вывести их как
foreach ($numbers as $v)
    echo $file[$v];
0
Hello Kitty
 Аватар для WhiteMind
690 / 562 / 402
Регистрация: 12.02.2016
Сообщений: 1,436
Записей в блоге: 1
24.02.2016, 20:51
Цитата Сообщение от pav1uxa Посмотреть сообщение
заменяется
не совсем.
при
count(file("file.txt"));
php выкачает весь файл, потом разобьет его на на строки, потом создаст асоциативный(а они все же такие…) массив и если строк много может подпрыгнуть память. если строк очччень многа будет своп и count(file("file.txt")); отработает медленней
PHP
1
2
3
4
5
6
7
8
9
function FileGetCount( $path ) {
* * if ( $f = fopen( $path , "r" ) ) {
* * * * $counter = 0;
* * * * while (fgets($f)) { $counter++; }
* * * * fclose($f);
* * * * return $counter;
* * }
* * return false;
}
0
0 / 0 / 0
Регистрация: 30.05.2011
Сообщений: 16
24.02.2016, 21:26  [ТС]
Цитата Сообщение от pav1uxa Посмотреть сообщение
Вот это Ваше предложение оно как бы говорит в мою пользу, понимаете?
Нет, не понимаю Я же объясняю, что разница между непосредственной работой с файлом и с предварительным его прогоном через массив (file('файл')) составляет сотые секунды, но использование массива дополнительно съедает и ОЗУ в двойном размере от размера самого файла. И не важно, сколько раз цикл гонял по файлу, главное, что скрипт использовал процессор одно и то же время, но во втором случае ещё и ОЗУ сожрал. Может мы о разных вещах толкуем?

WhiteMind
А что в вашем скрипте означают записи return [] и result = [] ? И вообще, честно говоря, думал что задача как-то проще решается. Очень уж мудрёно выходит. Может и правда смириться с неким жором ОЗУ в пользу простоты кода? Не люблю код, в котором потом сложно разобраться, если нужно. Не все мы математику в школе хорошо учили
0
Hello Kitty
 Аватар для WhiteMind
690 / 562 / 402
Регистрация: 12.02.2016
Сообщений: 1,436
Записей в блоге: 1
24.02.2016, 22:10
Цитата Сообщение от sMario Посмотреть сообщение
Не все мы математику в школе хорошо учили
нет тут математики. примитивная рекурсия.
return [] - синтаксис php >= 5.4.x
аналог return Array();
0
0 / 0 / 0
Регистрация: 30.05.2011
Сообщений: 16
24.02.2016, 22:20  [ТС]
Цитата Сообщение от WhiteMind Посмотреть сообщение
return [] - синтаксис php >= 5.4.x
аналог return Array();
Всё, теперь понял. Большое спасибо. Код работает быстро (на 10 тыс. строк у меня вышло 0.1 сек.) и не использует ОЗУ (про копейки не говорим)!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
24.02.2016, 22:20
Помогаю со студенческими работами здесь

Случайный выбор файла из ресурсов
Вот кусок кода, который проигрывает случайный файл, добавленный в ресурсы: System.Media.SoundPlayer Sound = new...

Занесения данных из текстового файла в массив
Здравствуйте, мне нужно из текстового файла занести в массив, после чего это вывести в StringGrid Сколько примеров я тут не рассматривал,...

Дан случайный массив. Сформировать новый массив на основе данного, но без дубликатов
вот код package com.company; import java.lang.String; import java.util.Random; class Main { public static void main(String...

Как обойтись без метода Свернуть() для подсчет уникальных строк в ТЗ
ТЗ.Колонки.Добавить(&quot;Колзаписей&quot;); ТЗ.Колонки.Добавить(&quot;ДлинаАдреса&quot;); ТЗ.ЗаполнитьЗначения(1,&quot;Колзаписей&quot;); ...

Случайный выбор определённых слов при копировании одного файла в другой
Допустим копируется один файл в другой.copy /Y file1.txt file2.txt, необходимо, если к примеру в тексте найдено любое совпадение слов (луг,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru