Объединение нескольких строк CSV с почти пустыми полями в одну строку за отметку времени - PullRequest
0 голосов
/ 16 октября 2018

У меня проблема с преобразованием "некрасивого" CSV в "симпатичный".Например, у меня есть:

something,epochtime,time-human-readable,some,header,for,the,values,here
same,time-a,don-t_care,a,b,,,,
same,time-a,don-t_care,,,,,c,
same,time-a,don-t_care,,,,,,d
same,time-a,don-t_care,,,e,f,,
same,time-b,don-t_care,g,h,,,,
same,time-b,don-t_care,,,i,j,,
same,time-b,don-t_care,,,,,,k
same,time-b,don-t_care,,,,,l,
same,time-c,don-t_care,,,m,n,,
same,time-c,don-t_care,,,,,o,
same,time-c,don-t_care,p,q,,,,
same,time-c,don-t_care,,,,,,r

Но мне нужно:

something,epochtime,time-human-readable,some,header,for,the,values,here
same,time-a,don-t_care,a,b,e,f,c,d
same,time-b,don-t_care,g,h,i,j,l,k
same,time-c,don-t_care,p,q,m,n,o,r

Поведение данных:

  • В столбцах, о которых идет речь, содержится целое число со знаком или число с плавающей запятой(за исключением первого и третьего столбца, которые имеют тип string и не являются частью проблемы).
  • Всегда ровно 1 значение на столбец и время эпохи.(Можно интерпретировать пустые поля как 0 и суммировать все значения в одном столбце, принадлежащие одному периоду времени.)
  • Значения одного времени эпохи распространяются на одно и то же количество строк каждый раз.
  • Значения, принадлежащиедо одной эпохи может всегда отображаться разбросанным по строкам в одном и том же шаблоне (в отличие от примера) ... но это не гарантируется.

IЯ попытался решить эту проблему с помощью моего ограниченного навыка, используя sed / awk, но безрезультатно.

Любое решение, которое может быть выполнено crontab, приветствуется, в то время как bash / sed / awk / perl / python или любое другоеget install ... "способный инструмент командной строки является предпочтительным.ОС хоста - XUbuntu 16.04 LTS.

Приложение: (2018-10-16 13:55 UTC)

  • Строки отсортированы в хронологическом порядке в соответствии с эпохой
  • Значениясгруппированы по epochtime
  • Несмотря на то, что первый и третий столбцы содержат строку, они состоят из букв, чисел и - или _, без пробелов или , -> без строковой головной боли
    , т. е.dummy,1539697764,2018-10-16_13-49-24,p,q,,,,

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

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

#!/usr/bin/perl
use strict;
use warnings;
# Install the following non-core modules through your
# OS package manager or favorite CPAN client.
use List::MoreUtils qw/pairwise/;
use Text::CSV;

my $csv = Text::CSV->new({ auto_diag => 2, blank_is_undef => 1 });
my $header = <>;
print $header;
my $merged = $csv->getline(\*ARGV);
while (my $cols = $csv->getline(\*ARGV)) {
  if ($merged->[1] ne $cols->[1]) {
    $csv->say(\*STDOUT, $merged);
    $merged = $cols;
  } else {
    $merged = [ pairwise { $a // $b } @$merged, @$cols ];
  }
}
$csv->say(\*STDOUT, $merged);

работает:

$ perl merge.pl data.csv
something,epochtime,time-human-readable,some,header,for,the,values,here
same,time-a,don-t_care,a,b,e,f,c,d
same,time-b,don-t_care,g,h,i,j,l,k
same,time-c,don-t_care,p,q,m,n,o,r
0 голосов
/ 17 октября 2018

Другое решение Perl:

open $CSV, "<" , "ugly.csv";
@R=();
  while (<$CSV>) {
      if ($.==1 ) { print ; next; }
      chomp;
      @F=split(/,/,$_);
      $k=join(",",@F[0..2]);
      if( $k ne $prevk ) { @R=() }
      push(@R,@F[3..9],"|");
      $hash{"$k"}=join(",",@R);
      $prevk=$k;
    }
foreach $val (sort keys %hash)
{
 @arr=split(/\|/,$hash{$val});
 $x=join("",reverse sort @arr);
 $x=~s/(^[,])|([,]{2,})/$1 eq "," ? "" : ","/eg;
 print "$val,$x\n";
}

Shell Shell:

$ perl -f ugly_csv.pl
something,epochtime,time-human-readable,some,header,for,the,values,here
same,time-a,don-t_care,a,b,e,f,c,d,
same,time-b,don-t_care,g,h,i,j,l,k,
same,time-c,don-t_care,p,q,m,n,o,r,
0 голосов
/ 16 октября 2018
$ cat tst.awk
BEGIN { FS=OFS="," }
$2 != prev { if (NR>1) prt(); prev=$2 }
{
    for (i=1; i<=NF; i++) {
        if ($i != "") {
            rec[i] = $i
        }
    }
}
END { prt() }
function prt() {
    for (i=1; i<=NF; i++) {
        printf "%s%s", rec[i], (i<NF ? OFS : ORS)
    }
    delete rec
}

$ awk -f tst.awk file
something,epochtime,time-human-readable,some,header,for,the,values,here
same,time-a,don-t_care,a,b,e,f,c,d
same,time-b,don-t_care,g,h,i,j,l,k
same,time-c,don-t_care,p,q,m,n,o,r
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...