Algorithm 将(键、值)数据转换为csv格式

Algorithm 将(键、值)数据转换为csv格式,algorithm,perl,optimization,Algorithm,Perl,Optimization,假设我们有一个具有以下格式的数据文件: $ cat data.txt a:23 b:25 c:76 d:45 a:21 b:24 c:25 a:20 d:52 e:75 f:75 g:52 ... (many lines) ... 假设此文件太大而无法读入内存,那么将此数据转换为csv格式的最快方法是什么 输出应包含包含文件中所有可能“键”的标题;如果某一行上缺少某个键,则该键在该行上的值应等于零。例如: $ cat csv.txt //a,b,c,d,e,f,g 2

假设我们有一个具有以下格式的数据文件:

$ cat data.txt
  a:23 b:25 c:76 d:45
  a:21 b:24 c:25 
  a:20 d:52 e:75 f:75 g:52
  ...
  (many lines)
  ...
假设此文件太大而无法读入内存,那么将此数据转换为csv格式的最快方法是什么

输出应包含包含文件中所有可能“键”的标题;如果某一行上缺少某个键,则该键在该行上的值应等于零。例如:

$ cat csv.txt
//a,b,c,d,e,f,g
23,25,76,45,0,0,0
21,24,25,0,0,0,0
20,0,0,52,75,75,52
... 
(many lines)
... 
这是我试过的。这是可行的,但我觉得所有的循环都在减慢我的速度。有没有一种更快、优化的方法可以做到这一点?我使用了Perl,但我当然愿意切换到Python或其他东西

# transform_test.pl 

# build set of all used keys.
my %usedKey;
open FILE, "data.txt";
while(<FILE>) {
        chomp $_;
        my @fields = split;
        foreach my $field (@fields) {
                my ($key,$value) = split(":",$field);
                $usedKey{$key} = 1;
        }
}
close FILE;

# build array of all used keys, but sorted.
my @sorted_keys = sort keys %usedKey;

# print header
my $header = "//";
foreach my $key (@sorted_keys) { $header .= "$key,"; }
chop $header;
print "$header\n";

# read through file again to transform the data;
open FILE, "data.txt";
while(<FILE>) {
        chomp $_;

        # build current line hash
        my @fields = split;
        my %currentData;
        foreach my $field (@fields) {
                my ($key,$value) = split(":",$field);
                $currentData{$key} = $value;
        }

        # build string by looping over all sorted keys.
        my $toPrint = "";
        foreach my $key (@sorted_keys) {
                $toPrint .= defined $currentData{$key} ? "$currentData{$key}," : "0,"; 
        }
        chop $toPrint;
        print "$toPrint\n";
}
#transform_test.pl
#生成所有已用密钥的集合。
我的%usedKey;
打开文件“data.txt”;
while(){
大口大口;
我的@fields=split;
foreach my$字段(@fields){
我的($key,$value)=拆分(“:”,$field);
$usedKey{$key}=1;
}
}
关闭文件;
#生成所有已使用键的数组,但已排序。
my@sorted_keys=排序键%usedKey;
#打印页眉
我的$header=“/”;
foreach my$key(@sorted_keys){$header.=“$key,”;}
切掉$header;
打印“$header\n”;
#再次读取文件以转换数据;
打开文件“data.txt”;
while(){
大口大口;
#生成当前行哈希
我的@fields=split;
我的%currentData;
foreach my$字段(@fields){
我的($key,$value)=拆分(“:”,$field);
$currentData{$key}=$value;
}
#通过循环所有已排序的键来构建字符串。
我的$toPrint=“”;
foreach my$key(@sorted_key){
$toPrint.=定义的$currentData{$key}?”$currentData{$key},:“0”;
}
印章$toPrint;
打印“$toPrint\n”;
}

考虑到您的规格,这似乎很管用:

#!/usr/bin/env perl

use strict;
use warnings 'all';

my @header = qw ( a b c d e f g h i j ); 

print join ",", @header,"\n";
while ( <DATA> ) { 
    my %row = map { /(\w+):(\d+)/ } split;
    print join ",", map { $_ // 0 } @row{@header},"\n";

}

__DATA__
  a:23 b:25 c:76 d:45
  a:21 b:24 c:25 
  a:20 d:52 e:75 f:75 g:52
不过,它确实依赖硬编码密钥。如果需要动态关键帧,则。。。这取决于你的文件有多大,因为你需要处理它两次

#!/usr/bin/env perl

use strict;
use warnings 'all';
use Data::Dumper;

my %usedKeys;
my @rows;

while (<DATA>) {
   my %row = map {/(\w+):(\d+)/} split;
   push @rows, \%row;
   $usedKeys{$_}++ for keys %row;
}

my @header = sort keys %usedKeys;
print join ",", @header, "\n";
foreach my $row (@rows) {
   print join ",", map { $_ // 0 } @{$row}{@header}, "\n";
}
__DATA__
  a:23 b:25 c:76 d:45
  a:21 b:24 c:25 
  a:20 d:52 e:75 f:75 g:52

好吧,考虑到你的规格,这似乎很管用:

#!/usr/bin/env perl

use strict;
use warnings 'all';

my @header = qw ( a b c d e f g h i j ); 

print join ",", @header,"\n";
while ( <DATA> ) { 
    my %row = map { /(\w+):(\d+)/ } split;
    print join ",", map { $_ // 0 } @row{@header},"\n";

}

__DATA__
  a:23 b:25 c:76 d:45
  a:21 b:24 c:25 
  a:20 d:52 e:75 f:75 g:52
不过,它确实依赖硬编码密钥。如果需要动态关键帧,则。。。这取决于你的文件有多大,因为你需要处理它两次

#!/usr/bin/env perl

use strict;
use warnings 'all';
use Data::Dumper;

my %usedKeys;
my @rows;

while (<DATA>) {
   my %row = map {/(\w+):(\d+)/} split;
   push @rows, \%row;
   $usedKeys{$_}++ for keys %row;
}

my @header = sort keys %usedKeys;
print join ",", @header, "\n";
foreach my $row (@rows) {
   print join ",", map { $_ // 0 } @{$row}{@header}, "\n";
}
__DATA__
  a:23 b:25 c:76 d:45
  a:21 b:24 c:25 
  a:20 d:52 e:75 f:75 g:52

如果文件太大,无法放入内存,则需要两个过程:第一个过程构建所有列名的列表,第二个过程将每行转换为相应的CSV记录。我会这样写

此程序希望输入文件的路径作为命令行上的参数,并将输出写入标准输出,标准输出可在命令行上重定向

使用严格;
使用“全部”警告;
使用Fcntl':seek';
我的($file)=@ARGV;

打开我的$fh,“如果文件太大,无法放入内存,则需要两个过程:第一个过程是构建所有列名的列表,第二个过程是将每行转换为相应的CSV记录。我会这样写

此程序希望输入文件的路径作为命令行上的参数,并将输出写入标准输出,标准输出可在命令行上重定向

使用严格;
使用“全部”警告;
使用Fcntl':seek';
我的($file)=@ARGV;

打开我的$fh,'你能对标题内容做出假设吗?为什么要用python标记?我会接受python解决方案,这可能更自然。我将删除标记,因为我实际上没有编写任何python,though@Sobrique不,假设在实际解析
data.txt
中的键之前,您对标题中包含的内容一无所知。您能对标题内容做出假设吗?为什么要用python标记?我愿意使用python解决方案,这可能更自然。我将删除标记,因为我实际上没有编写任何python,though@Sobrique不,假设在实际解析
data.txt
中的键之前,您对头中包含的内容一无所知。好吧,我完全同意这样一个事实:我们必须扫描文件两次。但是,有没有比我上面尝试的更有效的方法来构建“current line”散列或构建要打印的字符串呢?添加了最后一个计算头字段的示例。老实说,我不认为这里面有太多东西,因为你的“昂贵”部分将是文件IO。好吧,我完全接受这样一个事实,我们将不得不扫描文件两次。但是,有没有比我上面尝试的更有效的方法来构建“current line”散列或构建要打印的字符串呢?添加了最后一个计算头字段的示例。老实说,我不认为这里面有什么,因为你的“昂贵”部分将是文件IO。