Perl: шаблон для анонимного массива? - PullRequest
2 голосов
/ 12 октября 2010

У меня есть скрипт Perl для построчного анализа многих мегабайт данных.

В качестве примера я буду использовать закрытие среднего по Доу-Джонсу по дням для нескольких строк.

Данные читаются, а расположение данных в файле простое.В этом примере это:

Date Open High Low Close Volume Adj-Close

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

Date Open Adj-Close %change [more data to be added]

Вот пример кода:

use warnings; use strict;

my @trades;

while(<DATA>) {
    chomp;
 my ($year,$mon,$day,$open,$high,$low,$close,$vol,$ad_close);

 if(($year,$mon,$day,$open,$high,$low,$close,$vol,$ad_close)=
   /^(\d+)-(\d+)-(\d+),    #date YYYY-MM-DD
   (\d+\.\d+),             #open
   (\d+\.\d+),             #High
   (\d+\.\d+),             #Low
   (\d+\.\d+),    #Close
   (\d+),     #Vol
   (\d+\.\d+)/x)    #adj cl
    {
    my $drp=($ad_close-$open)/$open;
# HERE Created:    
    push @trades, [$year,$mon,$day,$open,$ad_close,$drp];     
   }
   else {
      print "$_ does not match...\n";
   }   
}

# widely separated and in multiple places... 

foreach my $trade_ref (@trades) {
#HERE Referenced
 my ($year,$mon,$day,$open,$ad_close,$drp)=@$trade_ref;

 print "$year-$mon-$day $open,$ad_close,$drp\n";          
}

# Dow Jones data by day...
__DATA__
2010-10-08,10948.50,11055.29,10901.12,11006.48,3871420000,11006.48
2010-10-07,10968.41,11032.17,10878.04,10948.58,3910550000,10948.58
2010-10-06,10936.79,11015.86,10880.08,10967.65,4073160000,10967.65
2010-10-05,10752.63,10982.98,10752.63,10944.72,4068840000,10944.72
2010-10-04,10828.85,10875.54,10682.66,10751.27,3604110000,10751.27
2010-10-01,10789.72,10907.41,10759.14,10829.68,4298910000,10829.68
2010-09-30,10835.96,10960.99,10732.27,10788.05,4284160000,10788.05
2010-09-29,10857.98,10901.96,10759.75,10835.28,3990280000,10835.28
2010-09-28,10809.85,10905.44,10714.03,10858.14,4025840000,10858.14
2010-09-27,10860.03,10902.52,10776.44,10812.04,3587860000,10812.04
2010-09-24,10664.39,10897.83,10664.39,10860.26,4123950000,10860.26
2010-09-23,10738.48,10779.65,10610.12,10662.42,3847850000,10662.42
2010-09-22,10761.11,10829.75,10682.40,10739.31,3911070000,10739.31
2010-09-21,10753.39,10844.89,10674.83,10761.03,4175660000,10761.03
2010-09-20,10608.08,10783.51,10594.38,10753.62,3364080000,10753.62
2010-09-17,10595.44,10689.29,10529.67,10607.85,4086140000,10607.85
2010-09-16,10571.75,10624.58,10499.43,10594.83,3364080000,10594.83
2010-09-15,10526.42,10609.21,10453.15,10572.73,3369840000,10572.73
2010-09-14,10544.81,10622.69,10460.34,10526.49,4521050000,10526.49
2010-09-13,10458.60,10605.73,10458.45,10544.13,4521050000,10544.13
2010-09-10,10415.01,10502.80,10376.34,10462.77,3061160000,10462.77
2010-09-09,10388.22,10515.86,10359.23,10415.24,3387770000,10415.24
2010-09-08,10338.57,10460.50,10318.93,10387.01,3224640000,10387.01
2010-09-07,10446.80,10448.99,10304.44,10340.69,3107380000,10340.69
2010-09-03,10321.92,10484.71,10321.92,10447.93,3534500000,10447.93
2010-09-02,10270.08,10350.98,10211.80,10320.10,3704210000,10320.10
2010-09-01,10016.01,10305.87,10016.01,10269.47,4396880000,10269.47
2010-08-31,10006.42,10101.53,9915.73,10014.72,4038770000,10014.72

В месте кода, обозначенного # ЗДЕСЬ, обратите внимание, чтоСначала я помещаю анонимный массив в другой именованный массив для последующего доступа.Позже (намного позже в реальной программе) я обращаюсь к тому же массиву по ссылке.

До сих пор я только что вырезал текст "шаблона" [$year,$mon,$day,$open,$ad_close,$drp] из первого # ЗДЕСЬ и вручную вставил my ($year,$mon,$day,$open,$ad_close,$drp)=@$trade_ref; в другие # ЗДЕСЬ в программе.Должен быть лучший способ ...

Есть ли способ, которым я могу получить шаблон анонимного массива, который я нажимаю, чтобы он автоматически вызывался упорядоченным образом в других случаях через сценарий?В реальном скрипте анализируемые результаты, такие как $drp, меняются, и я хочу, чтобы изменение в создании данных было корректно обработано более поздними процедурами, даже если я не изменяю my ($year,$mon,$day,$open,$ad_close,$drp)=@$trade_ref; Если это была программа на C,определение может быть макросом в одном месте ...

Я думаю о добавлении анонимного хеша вместо массива с хешем, имеющим пары имя / значение, которые имеют имя значения, а затем значение этогозначение.Теоретически я знаю, что это сработает, но мне кажется расточительным и медленным.В реальном наборе данных содержится приблизительно 2 ГБ данных, и я могу быстро просмотреть их с помощью текущего проекта.

Есть ли лучший способ?

Ответы [ 4 ]

4 голосов
/ 12 октября 2010
  1. Hashrefs, вероятно, не такие медленные или расточительные, как вы думаете.
  2. Подход POE:
    use constant (YEAR => 0, MON => 1, DAY => 2, ...);
    $trade_ref->[YEAR] и т. Д.
3 голосов
/ 12 октября 2010
use strict; use warnings;
use constant {
    YEAR => 0, MON      => 1, DAY => 2,
    OPEN => 3, AD_CLOSE => 4, DRP => 5,
};

my @trades;
while(<DATA>) {
    chomp;
    my $dow = parse_dow( $_ );
    push @trades, $dow if @$dow;
}

print "@{$_}[YEAR, MON, DAY, OPEN, AD_CLOSE, DRP]\n"
for @trades;

sub parse_dow {
    my ($dow) = @_;

    my ($date, $open, $high, $low, $close, $vol, $ad_close)
    = split /,/, $dow;        
    my ($year, $mon, $day) = split /-/, $date;
    my $drp = ( $ad_close - $open ) / $open;

    return [$year, $mon, $day, $open, $ad_close, $drp];
}

__DATA__
2010-10-08,10948.50,11055.29,10901.12,11006.48,3871420000,11006.48
2010-10-07,10968.41,11032.17,10878.04,10948.58,3910550000,10948.58
2010-10-06,10936.79,11015.86,10880.08,10967.65,4073160000,10967.65
1 голос
/ 13 октября 2010

Благословленный массив не будет намного более загруженным, чем необлаженный массив.

package Trade;
use strict;
use warnings;
use English qw<@LAST_MATCH_START @LAST_MATCH_END>;

my @slots = qw<year month day open high low close vol ad_close drop>;
my %slot_for
    = (( map { $slots[$_] => $_ } 0..$#slots )
      , ( map { $_ => -1 } qw<date> )
      )
    ;

foreach my $i ( 0..$#slots ) {
    my $name = $slots[$i];
    no strict 'refs';
    *$name = sub {
        my ( $self, $value ) = @_;
        my $slotr = \$self->[$i];
        return $$slotr unless $#_;
        my $old = $$slotr;
        $$slotr = $value;
        return $$slotr;
    };
}

my @trades;
my %format_for;

sub trades { return @{[ @trades ]} };

sub new {
    my $class = shift;
    my @args  = @_;

    if ( @args == 0 ) {
        $args[0] = $_;
    }
    if ( @args == 1 ) {
        my $line = shift @args;
        @args
            = $line =~
              m/^(\d+)-(\d+)-(\d+), #date YYYY-MM-DD
                 (\d+\.\d+),        #open
                 (\d+\.\d+),        #High
                 (\d+\.\d+),        #Low
                 (\d+\.\d+),        #Close
                 (\d+),             #Vol
                 (\d+\.\d+)
              /x
            ;
        my ( $open, $ad_close ) = @args[3,8];
        push @args, ( $ad_close - $open ) / $open;
    }

    my $self = bless \@args, $class;
    push @trades, $self;
    return $self;
}

sub format {
    my $self   = shift;
    my $format = shift;
    my $format_ref = $format_for{ $format };
    unless ( $format_ref ) {
        my @format_list;
        my $fmt = $format;
        while ( $fmt =~ m/\$(\w+)/g ) {
            next unless exists $slot_for{ $1 };
            push @format_list, \&$1;
            substr( $fmt, $LAST_MATCH_START[0], $LAST_MATCH_END[0] - $LAST_MATCH_START[0], '%s' );
            pos( $fmt ) = $LAST_MATCH_START[0] + 2;
        }
        $fmt =~ s/\\n/\n/gm;
        $format_ref
            = $format_for{ $format }
            = { format => $fmt, list => \@format_list }
            ;
    }
    return $format unless $format_ref->{list};
    my ( $fmt, $format_list ) = @$format_ref{ qw<format list> };
    return sprintf( $fmt, map { $_->( $self ) } @$format_list );
}

sub date {
    my $str = join( '-', &year, &month, &day );
    return $str;
}

package main;

Trade->new while <DATA>;

print $_->format( '$date $open,$ad_close,$drop\n' ) foreach Trade->trades();
__DATA__
2010-10-08,10948.50,11055.29,10901.12,11006.48,3871420000,11006.48
2010-10-07,10968.41,11032.17,10878.04,10948.58,3910550000,10948.58
2010-10-06,10936.79,11015.86,10880.08,10967.65,4073160000,10967.65
2010-10-05,10752.63,10982.98,10752.63,10944.72,4068840000,10944.72
2010-10-04,10828.85,10875.54,10682.66,10751.27,3604110000,10751.27
2010-10-01,10789.72,10907.41,10759.14,10829.68,4298910000,10829.68
2010-09-30,10835.96,10960.99,10732.27,10788.05,4284160000,10788.05
2010-09-29,10857.98,10901.96,10759.75,10835.28,3990280000,10835.28
2010-09-28,10809.85,10905.44,10714.03,10858.14,4025840000,10858.14
2010-09-27,10860.03,10902.52,10776.44,10812.04,3587860000,10812.04
2010-09-24,10664.39,10897.83,10664.39,10860.26,4123950000,10860.26
2010-09-23,10738.48,10779.65,10610.12,10662.42,3847850000,10662.42
2010-09-22,10761.11,10829.75,10682.40,10739.31,3911070000,10739.31
2010-09-21,10753.39,10844.89,10674.83,10761.03,4175660000,10761.03
2010-09-20,10608.08,10783.51,10594.38,10753.62,3364080000,10753.62
2010-09-17,10595.44,10689.29,10529.67,10607.85,4086140000,10607.85
2010-09-16,10571.75,10624.58,10499.43,10594.83,3364080000,10594.83
2010-09-15,10526.42,10609.21,10453.15,10572.73,3369840000,10572.73
2010-09-14,10544.81,10622.69,10460.34,10526.49,4521050000,10526.49
2010-09-13,10458.60,10605.73,10458.45,10544.13,4521050000,10544.13
2010-09-10,10415.01,10502.80,10376.34,10462.77,3061160000,10462.77
2010-09-09,10388.22,10515.86,10359.23,10415.24,3387770000,10415.24
2010-09-08,10338.57,10460.50,10318.93,10387.01,3224640000,10387.01
2010-09-07,10446.80,10448.99,10304.44,10340.69,3107380000,10340.69
2010-09-03,10321.92,10484.71,10321.92,10447.93,3534500000,10447.93
2010-09-02,10270.08,10350.98,10211.80,10320.10,3704210000,10320.10
2010-09-01,10016.01,10305.87,10016.01,10269.47,4396880000,10269.47
2010-08-31,10006.42,10101.53,9915.73,10014.72,4038770000,10014.72
0 голосов
/ 12 октября 2010

Возможно, также стоит выяснить, можете ли вы скрыть содержимое массива в благословенной ссылке на массив.Имея класс trades, помещая объекты массива в ваш массив @trades, а затем имея метод для возврата данных и цены, вы сможете скрыть некоторые проблемы, которые возникают у вас с дублированием кода, но с риском немного более медленного времени выполнения из-за методазвонки.Прямой вызов в массив с использованием именованной константы будет быстрее, и я предполагаю, что это важнее всего остального.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...