Цикл по набору данных и обработка пропущенных значений - PullRequest
0 голосов
/ 03 февраля 2010

Я перебираю большой файл данных и хотел бы определить тип переменной в каждом столбце, например, если это Intenger или Float и т. д. Он отлично работает, однако на данный момент он все еще очень простой, и я хотел бы добавить еще одну идею. До сих пор объявление переменной основано на второй строке набора данных. (Первый используется в качестве заголовка.) Вот начало кода:

#!/usr/bin/perl

use warnings;
use diagnostics;
use Getopt::Std;

getopts("i:s:t:") or die "bad options: $!";

if($opt_i) {
open INFILE, "< $opt_i";
chomp($headerline = <INFILE>);
$second = <INFILE>;
} else {
die "the input file has to be given\n";
}

if($opt_t) {
$tablename = $opt_t;
} else {
$tablename = $opt_i;
$tablename =~ s/\.\w+//;
}

if($opt_s) {
$sep = $opt_s;
} else {
$sep = ",";
}

$headerline =~ s/\"//g;
$headerline =~ s/\./\_/g;
@header = split/$sep/, $headerline;

$second =~ s/\"//g ;
@second = split/$sep/, $second;
@terms = split/$sep/, $second;
@types = split/$sep/, $second;

А теперь я реализовал небольшой цикл. Проблема в том, что я не знаю, как обрабатывать пропущенные значения, которые объявлены с NULL. В настоящий момент цикл просто присваивает "", то есть ничего, переменной $vartype[$j].

$j = 0;
while($j <= $#second) {
if ($types[$j] =~ /NULL/) {
$vartype[$j] = "";
} elsif($types[$j] =~ /[A-Za-z]/) {
$vartype[$j] = "varchar";
} elsif ($types[$j] =~ /\./) {
$vartype[$j] = "double";
} else {
$vartype[$j] = "int";
}
$j++;
}

Так, как я могу внедрить другую структуру цикла в существующий цикл, чтобы всякий раз, когда у меня было значение NULL в одном столбце, цикл считывал следующее значение в этом же столбце и делал это, пока не найдет число или слово. *

Пример моих данных будет, например:

Country.Name        Time.Name  AG.LND.AGRI.ZS   NY.GDP.MKTP.CD   NE.IMP.GNFS.ZS
Brunei Darussalam   1960       NULL             1139121335.16    3.46
Brunei Darussalam   1960       NULL             1677595756.64    0.9
Brunei Darussalam   1960       NULL             1488339328.59    4.19
Brunei Darussalam   1961       3.98             1869828587.8     3.14
Brunei Darussalam   1961       3.98             2346769422.22    3.38
Brunei Darussalam   1961       3.98             2363109706.3     3.17

Как уже упоминалось, цикл for использует только вторую строку для выбора типа переменной.

Теперь я хотел бы реализовать еще один цикл, чтобы, например, в третьем столбце (AG.LND.AGRI.ZS) он проходил через столбец, пока не обнаружит первое действительное значение, в данном случае 3.98. В данный момент цикл распознает отсутствующее значение, помеченное как NULL, и просто присваивает пустое значение.

Ответы [ 2 ]

2 голосов
/ 03 февраля 2010

Прекратить программирование как C.

for my $variable (@types) {
  if ($variable =~ /NULL/) {
    push(@vartype, undef);
  }
  elsif ($variable =~ /[A-Za-z]/) {
    push(@vartype, "varchar");
  }
  elsif ($variable =~ /\./) {
    push(@vartype, "double";
  }
  else {
    push(@vartype, "int");
  }
}

Хотя, для perl, вы действительно должны хранить связанные данные в структуре данных хэшей. Что-то вроде:

my $data = [ { value => 'NULL', type => undef },
             { value => 'a string', type => 'varchar' },
             { value => 9.5, type => 'double'},
             { value => 30, type => 'int'},
           ];
1 голос
/ 03 февраля 2010

Мне трудно понять, что вы пытаетесь сделать. Предполагая, что вы пытаетесь угадать типы столбцов на основе содержимого столбцов, вот способ сделать это. Важно не устанавливать ничего, когда поле равно NULL, пропустить поле, если вы уже определили его тип, и выйти из цикла, как только будут определены все типы полей.

#!/usr/bin/perl

use strict; use warnings;
use Scalar::Util qw(looks_like_number);

my @names = split ' ', scalar <DATA>;
my @types;

while ( <DATA> ) {
    chomp;
    my @values = split / {2,}/;

    for my $i ( 0 .. $#values ) {
        next if defined $types[$i];
        my $val = $values[$i];
        next if $val eq 'NULL';
        if ( $val =~ /^[0-9]+\z/ ) {
            $types[$i] = 'int';
        }
        elsif ( $val =~ /^[0-9.]+\z/
                and looks_like_number($val) ) {
            $types[$i] = 'double';
        }
        else {
            $types[$i] = 'varchar';
        }
    }
    last unless grep { not defined } @types;
}

print "$_\n" for @types;


__DATA__
Country.Name        Time.Name  AG.LND.AGRI.ZS   NY.GDP.MKTP.CD   NE.IMP.GNFS.ZS
Brunei Darussalam   1960       NULL             1139121335.16    3.46
Brunei Darussalam   1960       NULL             1677595756.64    0.9
Brunei Darussalam   1960       NULL             1488339328.59    4.19
Brunei Darussalam   1961       3.98             1869828587.8     3.14
Brunei Darussalam   1961       3.98             2346769422.22    3.38
Brunei Darussalam   1961       3.98             2363109706.3     3.17

Выход:

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