Xpoint
   [напомнить пароль]

Снова о сортировках

Метки: [без меток]
[удл]
2007-06-04 21:20:40 [обр] Andrej[досье]
Код работает. Но какой-то он некрасивый у меня получился. Может все это можно лучше и проще сделать? Помогите пожалуйста.
my %hash = ();
my %hash2 = ();
foreach my $fname (qw(javasc prims kasps kodes)) {
  open (IMEN,"<","$directory/cgds/${fname}.txt") or die "Can't open file $!\n";
       flock(IMEN,LOCK_SH);
for(my $ind=0; <IMEN>; $ind++ ) {
   last if $ind==10;
      chomp;
      my @temp=split(/\|/,$_);
      push @{$hash{$temp[4]}}, $_;
      push @{$hash2{$temp[5]}}, $_;
    }
  close(IMEN) or die "Can't close file $!\n";
}

my $counter=10;
foreach (sort {$b <=> $a} keys %hash) {
  foreach (@{$hash{$_}}) {
    last unless $counter--;
   my @temp=split(/\|/,$_);
     $temp[4] -= '3600';
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($temp[4]);
     $mon++;
     $year += 1900;
      $temp[4] = sprintf ("%.2ld/%.2ld/$year %.2ld:%.2ld:%.2ld",$mday,$mon,$hour,$min,$sec);
      if (length($temp[2]) > 9) { $temp[2] = substr($temp[2], 0, 9) . qq~...~; } 
      if (length($temp[1]) > 34) { $temp[1] = substr($temp[1], 0, 34) . qq~...~; }
     if ($counter eq '4') {print "<br><br>\n";}
    print "$temp[1] #$temp[5] $temp[2] $temp[4]<br>\n";
  }
  last if $counter<0;
}
print "<br><br>";
my $counter=10;
foreach (sort {$a <=> $b} keys %hash2) {
  foreach (@{$hash2{$_}}) {
    last unless $counter--;
   my @temp=split(/\|/,$_);
     $temp[4] -= '3600';
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($temp[4]);
     $mon++;
     $year += 1900;
      $temp[4] = sprintf ("%.2ld/%.2ld/$year %.2ld:%.2ld:%.2ld",$mday,$mon,$hour,$min,$sec);
      if (length($temp[2]) > 9) { $temp[2] = substr($temp[2], 0, 9) . qq~...~; } 
      if (length($temp[1]) > 34) { $temp[1] = substr($temp[1], 0, 34) . qq~...~; }

    if ($temp[5] eq '0') { print "$temp[1] #$temp[5] $temp[2] $temp[4]<br>\n"; }
  }
  last if $counter<0;
}
спустя 6 минут [обр] Andrej[досье]

Блин. Только сейчас заметил. Последняя

foreach (sort {$a <=> $b} keys %hash2) {
***
}

Она не только должно выводить все строчки с $temp[5] = 0 но и сортировать их по времени. Она этого не делает :(

спустя 16 часов [обр] Алексей Севрюков(198/1280)[досье]
Andrej[досье] А содержимое читаемых файлов самим придумать? Как можно разбираться в коде если не ясно что он читает и обрабатывает?
спустя 9 минут [обр] Andrej[досье]
Извините, вот:
1153231845|Name themes|AWWS|st@inbox.ru|1153728642|4|AWWS|xx|00
спустя 20 минут [обр] Алексей Севрюков(198/1280)[досье]
Andrej[досье] И саму задачу опишите ))
спустя 11 минут [обр] Andrej[досье]
У меня есть 4 файла (javasc prims kasps kodes)
Их нужно открыть, взять из каждого первые 10 строк. Далее отсортировать их по дате и вывести 10 штук в таком виде "$temp[1] #$temp[5] $temp[2] $temp[4]<br>". (Дата хранится в $temp[4], также после пятой строчки нужно вывести <br><br>)
После этого всего нужно еще раз вывести строки отсортированные по дате в которых $temp[5] = 0.
Вобщем-то и все.
спустя 7 часов [обр] Alexander O(122/460)[досье]
#!/usr/bin/perl --
use strict;
use warnings;


# Их нужно открыть, взять из каждого первые 10 строк.
sub get_10_lines {
  my @a;
  local @ARGV =  @_;
  while(<>) {
    push @a, $_;
    close ARGV if $. > 9;
  }
  @a;
}


my $directory = '.'; # какой-то путь, где есть cgds, в котором 4 файла (javasc prims kasps kodes)


# Далее отсортировать их по дате

my @a = map { "$_->[1] # $_->[5] $_->[2] $_->[4] <br>" }
          sort {$a->[4] <=> $b->[4] } #  Дата хранится в $temp[4]
            map {[split '\|']}
              get_10_lines
                map {"$directory/cgds/$_"} qw(javasc prims kasps kodes);

# и вывести 10 штук в таком виде
for(0..9) {
  print $a[$_];
  print '<br><br>' if $_ == 4; # после пятой строчки нужно вывести <br><br>
}


# еще раз вывести строки отсортированные по дате в которых $temp[5] = 0.
print $_ for grep /# 0 /, @a;

# Вобщем-то и все.
спустя 20 минут [обр] Andrej[досье]

Вау, нефига себе. :) клева, огромное вам спасибо. Хотя некоторые вещи не понятны. Но клева. :P
А вот еще, $temp[2] и $temp[1] при выводе в этом скрипте мне нужно ограничивать, у меня это так:

if (length($temp[2]) > 9) { $temp[2] = substr($temp[2], 0, 9) . qq~...~; } 
if (length($temp[1]) > 34) { $temp[1] = substr($temp[1], 0, 34) . qq~...~; }

Может можно как-то проще, если да то покажите пожалуйста как.

Также и со временем ($temp[4]) я его обрабатываю так:

     $temp[4] -= '3600';
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($temp[4]);
     $mon++;
     $year += 1900;
      $temp[4] = sprintf ("%.2ld/%.2ld/$year %.2ld:%.2ld:%.2ld",$mday,$mon,$hour,$min,$sec);

Может можно проще и лучше все это сделать?

спустя 2 часа 50 минут [обр] Alexander O(122/460)[досье]
sub mk_date {

    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = 
        localtime($_[0]-3600);

    return sprintf ("%.2ld/%.2ld/%d %.2ld:%.2ld:%.2ld", 
                     $mday, $mon+1, $year+1900, $hour, $min, $sec);
}

my @a = map { $_->[1] =~ s/^(.{34})....+/$1.../;
              $_->[2] =~ s/^(.{9})....+/$1.../;
              $_->[4] = mk_date($_->[4]);
              "$_->[1] # $_->[5] $_->[2] $_->[4] <br>" 
            }
            sort {$a->[4] <=> $b->[4] }
              map {[split '\|']}
                get_10_lines
                  map {"$directory/$_"} qw(javasc prims kasps kodes);
спустя 3 минуты [обр] Andrej[досье]
Спасибо огромное.
спустя 1 час 38 минут [обр] Алексей Севрюков(198/1280)[досье]
М Ну Вы господа отжигаете в основах :)
спустя 10 дней [обр] Andrej[досье]
# еще раз вывести строки отсортированные по дате в которых $temp[5] = 0.
print $_ for grep /# 0 /, @a;

Нет, нужно только 10 вывести.

Объясните пожалуйста, почему вот этот мой пример не работает:?

for(0..9) {
  print '+$hi[$_]+'  if $_->[5] == 0;
}

Can't use string ("0") as an ARRAY ref while "strict refs" in use at -bin\fo.pl line 58, <> line 8.

спустя 12 минут [обр] Алексей Севрюков(198/1280)[досье]
Andrej[досье] Все верно. $_ является переменной цикла и принимает значение от 0 до 9. А число не может быть ссылкой на массив, о чем Вам честно пишется в ошибке. Что Вы хотите сделать?
спустя 9 часов [обр] Andrej[досье]

Нужно вывести не больше 10 строк в которых $_->[5] равно 0
Пример от Alexander O:

# еще раз вывести строки отсортированные по дате в которых $temp[5] = 0.
print $_ for grep /# 0 /, @a;

Выводит все найденные строчки. (Если их больше 10 выводит больше 10).

спустя 3 дня [обр] Alexander O(122/460)[досье]
Andrej[досье]
my $cnt = 0;
foreach my $line ( @a  ) {
  if ( $line =~ /# 0 / ) {
    print $line;
    last if ++$cnt > 9;
  }   
}
спустя 19 часов [обр] Andrej[досье]
Спасибо! Появился еще один вопрос. Хочу сделать поддержку flock.
Немного непонятно где здесь происходит открытие. Я правильно сделал?
sub get_10_lines {
  my @a;
  local @ARGV =  @_;
    flock(ARGV,LOCK_SH); # на открытие
  while(<>) {
    push @a, $_;
    close ARGV if $. > 9;
  }
  @a;
}
спустя 1 день 13 часов [обр] Alexander O(122/460)[досье]

Andrej[досье]
Нет, не правильно. flock нужно делать на filehandle открытого файла, до первой операции чтения/записи.
При исполнении оператора <> происходит и открытие файла и чтение из него.
Поэтому если написать flock до <>, то это будет рано — у нас нет filehandle,
а если написать flock после <>, то будет уже поздно — строка из файла уже прочитана.

Так что для flock придется использовать обычный open. Cм. perldoc perlfaq5

спустя 3 дня [обр] Andrej[досье]
Alexander, а насколько безопасно использовать такой скрипт без flock? Не покалечит ли он мои текстовые файлики? Его будут запускать постоянно около 60 человек в минуту.
спустя 5 часов [обр] Alexander O(122/460)[досье]
flock необходим для тех процессов, которые пишут в файл. Если только читают, то можно без него.
Powered by POEM™ Engine Copyright © 2002-2005