Выравнивание таблицы данных, созданной из хэша Perl - PullRequest
1 голос
/ 03 октября 2011

Я пытаюсь написать скрипт для обработки выходных данных оборудования для поведенческого тестирования.Мне нужно, чтобы все данные были выровнены по отметке времени в результирующем файле CSV.В этом и заключается подвох: время запуска отличается между тестовыми прогонами (оно близко, но не точно - может быть отключено от нескольких секунд до нескольких минут).Я могу получить желаемый результат, и я думаю, что у меня есть хорошая идея относительно того, как я могу выровнять все переменные, но не знаю, как это реализовать.

Все данные находятся в хэше с двумя уровнями(% hash {id} {vars}) со всеми переменными, хранящимися как числа, для простоты (имена переменных читаются из массива на распечатке).После того, как все данные извлечены из входных файлов, скрипт просматривает хеш и распечатывает данные следующим образом:

Variable 1
ID #1   data1   data2   data3...
ID #2   data1   data2   data3...
...
Variable 2
...

и т. Д.

Это 24-часовые записи.Последний пункт данных (var = 20) для всех субъектов - светлый: данные читаются как «ВКЛ» или «ВЫКЛ» для дня и ночи.Лучший способ выравнивания, который я вижу, - это использовать световой маркер OFF для выравнивания данных.

Мое мышление таково:
1. Найти первую позицию для каждого идентификатора, для которого var '20' = 'OFF 'и позиция записи
2. Определите, какой идентификатор имеет наибольшую позицию для OFF (т. Е. Ту, которая начала запись раньше)
3. Добавляйте пустые пары значений для каждого другого объекта, пока позиция OFF не станет одинаковой длявсе.

Например, если данные записываются один раз в минуту и ​​у одного субъекта есть время ВЫКЛЮЧЕНИЯ, которое на 5 минут позже, чем у всех остальных, добавьте 5 пустых точек данных ко всем другим субъектам для выравнивания данных.

Это должно быть сделано для всех точек данных по каждому предмету, а не только для индикатора включения / выключения света.

Будет ли этот подход работать?И если да, то как я могу это реализовать?

** Обратите внимание, что мне нужно иметь возможность упаковать его как отдельный скрипт для запуска на нескольких компьютерах, поэтому я не могу рассчитывать на perl-модули, которые не 't устанавливается по умолчанию.

- редактировать по запросу: пример.Входные данные выглядят так (это файл CSV)

ID,     TIME,      DATA1,  DATA2,  DATA3, [...] ,  LIGHT  
Subj1,  10:00:00,  data1,  data2,  data3, [...] ,  ON  
Subj1,  10:00:30,  data1,  data2,  data3, [...] ,  ON  
Subj1,  10:01:00,  data1,  data2,  data3, [...] ,  OFF  
Subj1,  10:01:00,  data1,  data2,  data3, [...] ,  OFF  

Для другого субъекта данные могут выглядеть следующим образом:

ID,     TIME,      DATA1,  DATA2,  DATA3, [...] ,  LIGHT  
Subj2,  09:59:27,  data1,  data2,  data3, [...] ,  ON  
Subj2,  09:59:57,  data1,  data2,  data3, [...] ,  ON  
Subj2,  10:00:27,  data1,  data2,  data3, [...] ,  ON  
Subj2,  10:00:57,  data1,  data2,  data3, [...] ,  OFF  
Subj2,  10:01:27,  data1,  data2,  data3, [...] ,  OFF  

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

$VAR1 = {
         'Subj1' => {
                     '1' => [
                             data1
                             data1
                             ...
                             ]
                      '2' => [
                             data2
                             data2
                             ...
                             ]
                     ...
                     '20' => [
                             ON
                             ON
                             ...
                    }
         'Subj1' => {
                     '1' => [
                             data1
                             data1
                             ...
                             ]
                      '2' => [
                             data2
                             data2
                             ...
                             ]
                     ...
                     '20' => [
                             ON
                             ON
                             ...
                    }
        };

Данные выводятся с циклом foreach:

foreach my $k (sort {$a cmp $b} keys %data) { 
    print OUT $k, "\,";
    foreach my $d ( @{ $data{$k}{$i} } ) { print OUT $d, "\,"; }
    print OUT "\n";
    }

Вывод выглядит так:

TIME  
Subj1,  10:00:00,  10:00:30,  10:01:00,  10:01:30,
Subj2,  09:59:27,  09:59:57,  10:00:27,  10:00:57,  10:01:27,
DATA1
Subj1,  data1,  data1,  data1,  data1,  data1,  
Subj2,  data2,  data2,  data2,  data2,  data2,  data2,
[ ... all other data ... ]
LIGHT
Subj1,  ON,  ON,  OFF, OFF,
Subj2,  ON,  ON,  ON,  OFF, OFF,

Что мне нужно сделать, это выровнять все данные по столбцам ВКЛ / ВЫКЛ в LIGHT, добавив пустые значения следующим образом:

TIME  
Subj1,          ,  10:00:00,  10:00:30,  10:01:00,  10:01:30,
Subj2,  09:59:27,  09:59:57,  10:00:27,  10:00:57,  10:01:27,
DATA1
Subj1,       ,  data1,  data1,  data1,  data1,  data1,  
Subj2,  data2,  data2,  data2,  data2,  data2,  data2,
[ ... all other data ... ]
LIGHT
Subj1,    ,  ON,  ON,  OFF, OFF,
Subj2,  ON,  ON,  ON,  OFF, OFF,

Попытка выяснить, как лучше всего это сделать.Извините, это долго ...

Ответы [ 3 ]

1 голос
/ 04 октября 2011

Как вам это подходит?

Он использует List::Util::max, но это было стандартным некоторое время, и его легко написать самостоятельно, если у вас его нет.

use List::Util qw(max);
use strict;
use warnings;

my $ALLDATA = {
         'Subj1' => {
                     '1' => [
                             'data1',
                             'data1',
                             ],
                      '2' => [
                             'data2',
                             'data2',
                             ],
                     '20' => [
                             'ON',
                             'ON',
                             'OFF',
                             ]
                    },
         'Subj2' => {
                     '1' => [
                             'data1',
                             'data1',
                             ],
                      '2' => [
                             'data2',
                             'data2',
                             ],
                     '20' => [
                             'ON',
                             'ON',
                             'ON',
                             'OFF',
                             'OFF',
                             ]
                    },
        };

sub num_ons_before_first_off
{
    my $n = 0;
    foreach(@_)
    {
        last if $_ eq 'OFF';
        $n++;
    }
    return $n;
}

# store a 'numons' piece of data for each subject, for use later
foreach my $subject(values(%$ALLDATA))
{
    $subject->{'numons'} = num_ons_before_first_off(@{$subject->{'20'}}); 
}

# calculate the max 'numons' across all subjects
my $max_ons = max(map { $_->{'numons'} } values(%$ALLDATA));

foreach my $k(keys(%$ALLDATA))
{
    my $subject = $ALLDATA->{$k};

    #output leading blank entries
    print ',' x ($max_ons - $subject->{'numons'});

    #output the real data
    foreach my $data(@{$subject->{'20'}})
    {
        print "$data,";
    }
    print "\n";
}

Надеюсь, очевидно, как вы могли бы расширить это до остальной части ваших данных.

Вам нужен интервал, как он есть в вашем вопросе?Вы говорите, что это CSV, так что я думаю, нет.Я могу обновить, если это важно, хотя.

0 голосов
/ 04 октября 2011

Понял!«Макс» был ключом там.jwd, не знаю почему, но я не смог адаптировать ваш скрипт для работы с данными (постоянно получал ошибку «не могу использовать строку в качестве хеш-кода при строгой ошибке»).Но это дало мне вдохновение, в котором я нуждался.

При обработке файлов я реализовал счетчик, который увеличивается до достижения первого значения OFF.Это передается в хэш вместе с идентификатором субъекта в виде пары ключ-значение ($ offset {$ id} = $ count).

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

При выводе я использовал ваш код в качестве основы, чтобы добавить дополнительные запятые для заполнения данных.Заключительные соответствующие разделы выглядят так:

my $max_off = max values %offset;

foreach my $k ( keys %offset ) {
    $offset{$k} = $max_off - $offset{$k};
    }

foreach my $k (sort {$a cmp $b} keys %data) { 
    print OUT $k, "\,";
    print OUT ',' x ($offset{$k});
    foreach my $d ( @{ $data{$k}{$i} } ) { print OUT $d, "\,"; }
        print OUT "\n";
        }
    }

Делает именно то, что мне нужно.Спасибо за предложения!

0 голосов
/ 04 октября 2011

Это не ответ, но он не помещается в комментарии:

Когда вы говорите, что хотите «выровнять все данные по столбцам ВКЛ / ВЫКЛ в СВЕТЕ», вы имеете в виду выравнивание по правому краю всего?

Например, если у вас были эти данные:

Subj1,ON,ON,OFF,
Subj2,ON,ON,ON,OFF,OFF,

Будет ли это результат?

Subj1,   ,   , ON,  ON, OFF,
Subj2, ON, ON, ON, OFF, OFF,

Или вы хотите, чтобы это было так:

Subj1,   , ON, ON, OFF,    ,       <-- Note trailing blank entry
Subj2, ON, ON, ON, OFF, OFF,

То есть выравнивание первого 'OFF', как в вашем текстовом описании?

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