Модераторы: ginnie, korob2001
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Поиск и подсчет строк в большом файле 
:(
    Опции темы
Zynchak
Дата 14.12.2007, 16:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 14.12.2007

Репутация: нет
Всего: нет



Доброго дня всем!

У меня возникла проблема, а так как я только учусь писать на Перл, то и загвоздка серезная для меня.

Вот суть задачи:
Есть большой файл, около 30МБ. Требуется найти и подсчитать в нем все строки.
К примеру, берем первую строку и ищем сколько дублей во всем файле, результат записываем в файл в виде:

строка;количество

Дале вторую строку и такие же операции,  и так до конца файла, при том я вот незнаю как по несколько раз не считать одну и ту же строку, ведь мы ее могли уже считать.

Помогите мне пожалуста, очень нужно!

Заранее спасибо!
PM MAIL   Вверх
amg
Дата 14.12.2007, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 9
Всего: 50



Посмотри пока на этот код. Если не устроит, будем думать ( требуется много памяти и порядок строк произвольный будет).
Код

while (<FILE>) {
  chomp;
  $h{$_}++;
}
foreach (keys %h) {
  print "$_;$h{$_}\n";
}


Это сообщение отредактировал(а) amg - 14.12.2007, 17:07
PM MAIL   Вверх
Zynchak
Дата 19.12.2007, 09:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 14.12.2007

Репутация: нет
Всего: нет



У меня почему то ругается -
Global symbol "%h" requires explicit package name at search.pl line...

Добавлено через 2 минуты и 15 секунд
В принципе можно упростить задачу, сначало сделать еще один файл гдк будут только уникальные записи и уже от туда скчитывать кей а в первичном файле вести поиск.
PM MAIL   Вверх
amg
Дата 19.12.2007, 10:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 9
Всего: 50



Цитата(Zynchak @  19.12.2007,  09:28 Найти цитируемый пост)
У меня почему то ругается -Global symbol "%h" requires explicit package name at search.pl line...
Это из-за use strict; Добавь в начале my %h;


Это сообщение отредактировал(а) amg - 19.12.2007, 10:44
PM MAIL   Вверх
Ramirez
Дата 19.12.2007, 11:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 305
Регистрация: 18.1.2005
Где: Moscow, ExUSSR

Репутация: нет
Всего: 5



Если строки достаточно длинные (10-15 символов и более), то возможно будет эффективнее из строки сразу считать md5-хеш, и сравнивать и хранить в массиве уже их. Памяти будет требоваться меньше, но чуть больше будет нагружен процессор (вычисляя хеши) , но думаю что нагрузка будет несущественна.
PM ICQ   Вверх
amg
Дата 19.12.2007, 12:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 9
Всего: 50



Проверил вот такой код, печатающий только уникальные строки, сохраняющий порядок строк исходного файла и добавляющий в конец каждой строки номера строк исходного файла.
Код

while (<FILE>) {
  chomp;
  push @{$h{$_}}, $.;
}
foreach (sort {$h{$a}[0]<=>$h{$b}[0]} keys %h) {
  print "$_;@{$h{$_}}\n";
}
В принципе, ничего страшного. Для 30 Мб файла (450 тысяч строк, все уникальные) требуется 150 Мб памяти и 15 с (сортировка много времени занимает). Если бы было много одинаковых строк, было бы быстрее (и памяти меньше).

PM MAIL   Вверх
Zynchak
Дата 19.12.2007, 14:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 14.12.2007

Репутация: нет
Всего: нет



Вроде все получилось, вот код (search.pl):

#!/usr/bin/perl -w

use strict;
use warnings;

my %h;
my $path =$ARGV[0];
open( FILE, "< $path" ) or die $!;

while (<FILE>) {
  chomp;
  $h{$_}++;
}
foreach (keys %h) {
  print "$_;$h{$_}\n";
}


Запускаю вот так:

perl search.pl key.txt >> base.txt

В файле base.txt получаю вот такой результат, вроде все правильно работает:

keyword-a;65
keyword-b;2
keyword-c;7


PM MAIL   Вверх
amg
Дата 19.12.2007, 14:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 9
Всего: 50



Еще так можно:
Код

my (%h, @a);
while (<FILE>) {
  chomp;
  $h{$_}++ or push @a, $_;
}
foreach (@a) {
  print "$_;$h{$_}\n";
}
Займет немного больше памяти, но зато порядок строк будет такой же, как в исходном файле (если это важно). 
Этот вариант работает намного быстрее, чем мой предыдущий пример (который с сортировкой), да и памяти потребляет меньше.

Добавлено через 12 минут и 15 секунд
Цитата(Zynchak @  19.12.2007,  14:25 Найти цитируемый пост)
Запускаю вот так:
Кстати, именно для случаев такого запуска в перле имеется оператор <>. С ним файлы из аргументов сами откроются, просто
Код

while (<>) {
   ...
}


PM MAIL   Вверх
OutlawZ
Дата 28.4.2011, 02:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Awaiting Authorisation
Сообщений: 269
Регистрация: 19.10.2007

Репутация: нет
Всего: нет



Если придется работать с тремя файлами одновременно ? то как подсчитать количество совпавших строк? что бы к примеру программа выводила "Эта строка повторяется n-количество раз в файлах: file.txt, file2.txt" буду признателен за ответ.

Это сообщение отредактировал(а) OutlawZ - 28.4.2011, 02:24


--------------------
user posted image
user posted image
PM MAIL   Вверх
alezzz
Дата 30.4.2011, 18:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


сплю...
**


Профиль
Группа: Участник
Сообщений: 499
Регистрация: 17.8.2009

Репутация: нет
Всего: 14



усложните хеш, например:
Код

$h{$_}{$filename}++;


PM MAIL   Вверх
OutlawZ
Дата 1.5.2011, 00:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Awaiting Authorisation
Сообщений: 269
Регистрация: 19.10.2007

Репутация: нет
Всего: нет



Можно пример? а то у меня каша получается в плане том что счетчик совпадений перестал работать и дописывается просто к строке, что не есть хорошо, может сделать хеш хешей????


--------------------
user posted image
user posted image
PM MAIL   Вверх
SkoobyDoo
Дата 1.5.2011, 08:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 4.10.2007

Репутация: нет
Всего: нет



Код

#!/usr/bin/env perl

use strict;
use warnings;
use IO::File;

my (%h);

my $fh = new IO::File;
for my $f (@ARGV) {
  $fh->open("< $f");

  while (<$fh>) {
    chomp;
    s/^\s+//;
    s/\s+$//;
    next unless /[\w]+/;
    $h{$f}{$_}++;
  }

}
$fh->close;

for my $k (keys %h) {
  print $k, "\n";
  map { print "  ", $h{$k}{$_}, ": ", $_, "\n" } keys %{$h{$k}};
}


Это сообщение отредактировал(а) SkoobyDoo - 1.5.2011, 09:33
PM MAIL   Вверх
alezzz
Дата 1.5.2011, 09:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


сплю...
**


Профиль
Группа: Участник
Сообщений: 499
Регистрация: 17.8.2009

Репутация: нет
Всего: 14



Вот еще вариант, тут должно меньше памяти расходоваться на хэш:
Код

@files = @ARGV;

foreach $i (0..$#files){
    open $f, "<$files[$i]";
    while(<$f>){
        chomp;
        $lines{"$_"}[$i]++ if $_ !~ /^\s*$/;
    }
    close $f;
}

foreach $line (keys %lines){
    my $count;
    print "$line:\n";
    foreach $i (0..$#files){
        print "    $files[$i] - $lines{$line}[$i]\n" if $lines{$line}[$i];
        $count += $lines{$line}[$i];
    } 
    print"    all - $count\n";
}

PM MAIL   Вверх
OutlawZ
Дата 2.5.2011, 20:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Awaiting Authorisation
Сообщений: 269
Регистрация: 19.10.2007

Репутация: нет
Всего: нет



Всем спасибо, протестировал, доволен результатом.


--------------------
user posted image
user posted image
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl: Системное программирование"
korob2001
sharq
  • В этом разделе обсуждаются вопросы относящиеся только к системному программированию на Perl
  • Если ваш вопрос не относится к системному или CGI программированию, задавайте его в общем разделе
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.0805 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.