2010-11-19 30 views
3

我确信我已经完成了这项工作,并且有一些我忘记的东西,但是如何在特定列上对CSV文件进行排序?我对有或没有第三方Perl模块的答案感兴趣。主要方法没有,因为我不总是有权安装额外的模块。根据某一列对CSV进行排序?

示例数据:

name,25,female 
name,24,male 
name,27,female 
name,21,male

所需的2号数字列排序后,最终结果是:

name,21,male 
name,24,male 
name,25,female 
name,27,female

回答

0

当你提供你自己的比较代码,你可以排序任何东西。只需用正则表达式提取所需的元素,或者在这种情况下可能是分割,然后再比较。如果您有很多元素,我会将数据解析为列表列表,然后比较代码可以在不解析的情况下访问它。这将消除解析同一行,因为它与其他行进行比较。

11

由于CSV是一个相当复杂的格式,最好使用为我们做的工作

下面是使用Text::CSV模块的示例:

#!/usr/bin/env perl 

use strict; 
use warnings; 

use constant AGE => 1; 

use Text::CSV; 

my $csv = Text::CSV->new(); 

my @rows; 
while (my $row_ref = $csv->getline(\*DATA)) { 
    push @rows, $row_ref; 
} 

@rows = sort { $a->[AGE] <=> $b->[AGE] } @rows; 

for my $row_ref (@rows) { 
    $csv->combine(@$row_ref); 
    print $csv->string(), "\n"; 
} 

__DATA__ 
name,25,female 
name,24,male 
name,27,female 
name,21,male 
+3

很好的答案。运行'split /,/'真的很诱人,但对于Micro $ oft风格的CSV文件来说,这还不够好。我认为这对于Unix冒号分隔的foocap文件来说还不够好。 – tchrist 2010-11-19 02:55:41

+0

tchrist:对。很高兴收到你的评论,先生!谢谢。 :-) – 2010-11-19 03:12:13

+0

Perl新手。这是一个内存中的解决方案吗?有没有简单的方法可以用大文件做同样的事情?谢谢 – Gevorg 2013-06-04 17:55:30

6

还有DBD::CSV

#!/usr/bin/perl 

use strict; use warnings; 
use DBI; 

my $dbh = DBI->connect('dbi:CSV:', undef, undef, { 
    RaiseError => 1, 
    f_ext => '.csv', 
    csv_tables => { test => { col_names => [qw' name age sex '] } }, 
}); 

my $sth = $dbh->prepare(q{ 
    SELECT name, age, sex FROM test ORDER BY age 
}); 

$sth->execute; 

while (my @row = $sth->fetchrow_array) { 
    print join(',' => @row), "\n"; 
} 

$sth->finish; 
$dbh->disconnect; 

输出:

name,21,male 
name,24,male 
name,25,female 
name,27,female
-2

我会做这样的事情:

#!/usr/bin/perl 
use warnings; 
use strict; 

my @rows = map { chomp; [split /[,\s]+/, $_] } <DATA>; #read each row into an array 
my @sorted = sort { $a->[1] <=> $b->[1] } @rows; # sort the rows (numerically) by second column 

for (@sorted) { 
    print join(', ', @$_) . "\n"; # print them out as CSV 
} 

__DATA__ 
name,25,female 
name,24,male 
name,27,female 
name,21,male 
+2

好的,只要你的姓名中没有John Doe,Esq.'。 – reinierpost 2010-11-19 10:20:32

+1

我们有像CSV文件一样的CSV解析模块是有原因的。在一般情况下,以逗号分割就不够了。 – 2010-11-19 11:13:15

7

本着永远有另一种方式来做到这一点的精神,请记住,简单的旧的GNU排序可能就足够了。

$ sort -t, -k2 -n unsorted.txt 
name,21,male 
name,24,male 
name,25,female 
name,27,female 

当命令行参数是:

-t, # use comma as the record separator 
-k2 # sort on the second key (record) in the line 
-n # sort using numerical comparison (like using <=> instead of cmp in perl) 

如果你想有一个Perl的解决方案,将它包装在QX();-)

3

楼主问没有第三方模块(我认为它不代表CPAN)。虽然这种限制会严重限制您编写优秀的现代Perl代码的能力,但在这种情况下,可以使用(核心)Text :: ParseWords模块代替(非核心)Text :: CSV。因此,我们从Alan的例子中大量借鉴,我们得到:

#!/usr/bin/env perl 

use strict; 
use warnings; 

use Text::ParseWords; 

my @rows; 

while (<DATA>) { 
    push @rows, [ parse_line(',', 0, $_) ]; 
} 

@rows = sort { $a->[1] <=> $b->[1] } @rows; 

foreach (@rows) { 
    print join ',', @$_; 
} 

__DATA__ 
name,25,female 
name,24,male 
name,27,female 
name,21,male 
相关问题