Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Функция sort.


Автор: dixoNICH 27.10.2011, 21:36
Как с помощью функции sort можно отсортировать массв строк типа : "sdasdas 10.04.2008 dadsds" по дате? Как-то не понятно совсемушки smile Помогите мыслями, пожалуйста.

Автор: vadiml 27.10.2011, 22:01
Создать хеш в котором ключами будут вытянутые регэкспом даты из строк, а значениями сами строки, и сделать 
sort keys %этот_хеш

Автор: dixoNICH 27.10.2011, 23:21
@a = sort { $a cmp $b } keys %datehash;
print Dumper \@a;

$VAR1 = [
          '10.04.2001',
          '10.04.2007',
          '10.04.2009',
          '10.04.2010',
          '10.05.2008',
          '19.02.2008',
          '19.05.2008',
          '20.05.2008'
        ];
не-а

Автор: alezzz 28.10.2011, 08:01
Когда вытягиваете дату регуляркой, то отдельно вытягивайте день, месяц и год. В хеш сохраните в обратном порядке: ГГГГ.ММ.ДД. 

Автор: vadiml 28.10.2011, 09:26
Дату для сортировки обычно хранят в ISO формате
YYYY-MM-DD

Автор: dixoNICH 28.10.2011, 17:01
Спасибо!
Ещё вопрос по дате : Как перевести дату в секунды с помощью DateTime::Format::Epoch;?
Как из секунды в дату я понял, а обратно - неа.
Надо просто перебрать все даты в промежутке, лучше, чем перевод в секунды - ничего не знаю.

Автор: ginnie 28.10.2011, 17:21
dixoNICH, перебрать даты в промежутке можно используя неравенства, перевод в секунды не нужен.

Автор: dixoNICH 28.10.2011, 19:28
Не намекнёте, как? )

Автор: ginnie 28.10.2011, 19:32
dixoNICH, даны даты 20110123 20110223 20110323, как выбрать из них те, которые попадают в промежуток от 20110101 до 20110301?

Автор: dixoNICH 28.10.2011, 20:33
д >= 20110101 && д<=20110301

но, всё же, как перебирать то даты? )

Автор: ginnie 29.10.2011, 09:04
dixoNICH, прошу прощения, неправильно понял Ваш вопрос!
Для преобразования даты в unixtime можно использовать Time::Local::timegm(), которая вернет unixtime в UTC (где нет перехода на летнее время):
Код

$time = timegm($sec,$min,$hour,$mday,$mon,$year);

$mon должен быть в интервале [0..11] т.е. на 1 меньше реального, а год на 1900 меньше реального, это сделано для совместимости с функцией gmtime(), которая преобразует unixtime в дату.
Также можно использовать модуль Date::Calc (он XS, поэтому работает довольно быстро), для этой задачи подойдет функция
Код

($year,$month,$day) = Add_Delta_Days($year,$month,$day, $Dd);


Автор: dixoNICH 31.10.2011, 08:20
не смог с помощью этих функций получить время, которое выдаёт time (

Автор: ginnie 31.10.2011, 11:53
dixoNICH, напишите поконкретнее, что не удалось получить.

Автор: dixoNICH 31.10.2011, 12:48
уже сделал вручную)

Автор: ginnie 31.10.2011, 14:24
А "вручную" это как?

Автор: Suppir 31.10.2011, 14:42
Сортировка с помощью регулярных выражений:


Код

while(<DATA>){
    push(@lines, $_)
};


@sorted = sort {smart_sort()} @lines;

map {print} @sorted;
<>;



sub smart_sort{
    $a =~ / (\d\d).(\d\d).(\d\d\d\d) /;
    $date1 = $3.$2.$1;

    $b =~ / (\d\d).(\d\d).(\d\d\d\d) /;
    $date2 = $3.$2.$1;

    $date2 <=> $date1
}




__DATA__
sdasdas 10.04.2008 dadsds
sdasdas 01.02.2009 dadsds
sdasdas 31.12.2011 dadsds
sdasdas 15.05.2006 dadsds

Автор: dixoNICH 31.10.2011, 15:11
Код

use Exporter;
@ISA = qw(Exporter); 
@EXPORT_OK = qw(PROCESSOR); 
use DateTime::Format::Epoch;
sub islyear
{
  my $year = shift;

  $year = $year / 100 unless $year % 100;
  return !($year % 4);
}
sub getnday
{
  my $day = substr($_[0], 0, 2);
  my $month = substr($_[0], 3, 2);
  my $year = substr($_[0], 6, 4);
  $day =~ s/^0+//; $month =~ s/^0+//;
  my @days_per_month = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  $year++ if $year < 0;
  my $days = $day - 1;
  for (my $i = 0; $i < $month - 1; $i++)
  {
    $days += $days_per_month[$i];
  }
  $days++ if islyear($year) && $month > 2;
  $year--;
  $days += $year * 365;
  $days += int($year / 4);
  $days -= int($year / 100);
  $days += int($year / 400);

  return $days;
}
sub getseconds
{
  my $reqdate = $_[0];
  my $secondsinday = 86400;

  # на 1 января 1970 г.
  my $startday = 719162;

  return (getnday($reqdate) - $startday) * $secondsinday;
}
sub arraydate() {
    $d1 = $_[0];
    $d2 = $_[1];
    my $dt = DateTime->new( year => 1970, month => 1, day => 1 );
    my $formatter = DateTime::Format::Epoch->new(
                          epoch          => $dt,
                          unit           => 'seconds',
                          type           => 'int',   
                          skip_leap_seconds => 1,
                          start_at       => 0,
                          local_epoch    => undef,
                      );
    $f = getseconds($d1);
    while($f != getseconds($d2)) {
        $f += 24*3600;
        push @a, $formatter->parse_datetime($f);
    }
    for(@a) {
        /^(\d+)-(\d+)-(\d+)/;
        push @b, "$3.$2.$1";
    }
    return @b;
}

Автор: Egik2 31.10.2011, 15:22
Код

#!/usr/bin/perl
use Time::Local;
use strict;

my @array = ('10.02.2008', '11.02.2008', '12.02.2008', '01.01.2008');

my @newarray = sort is_time_between @array;

for my $ar (@newarray) {
    print $ar."\n";    
}

sub is_time_between {
   my $start_time = $a;
   my $end_time = $b; #string representing date, format for exampe Nov 17 07:06:42 2009 GMT
   my ($start_day, $start_month, $start_year) = $start_time =~ /(\d+).(\d+).(\d+)/;
   my ($end_day, $end_month, $end_year) = $end_time =~ /(\d+).(\d+).(\d+)/;
   my $start_epoch_time =  timegm(0, 0, 0, $start_day, $start_month, $start_year);
   my $end_epoch_time =  timegm(0, 0, 0, $end_day, $end_month, $end_year);
   if($start_epoch_time > $end_epoch_time) {
      return 1;
   }
   elsif ($end_epoch_time == $start_epoch_time) {
      return 0;
   }
   else {
      return -1;
   }
   
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)