我是perl编程的新手。 我想读取文件数据,然后在第1列上排序记录,然后在第2列(删除重复记录)和存储的已排序记录到另一个文件中。以下是我的数据
第一列和第二列由制表符分隔
user1 name user2 name
abc xyz
adc xyz
abc xyz
pqr tyu
xyz abc
tyu pqr
abc pqr
在这个例子中,我希望首先对user1名称和user2名称进行排序记录,并且在排序时我想要删除重复记录。
输出应如下
user1 name user2 name
abc pqr
abc xyz
adc xyz
pqr tyu
tyu pqr
xyz abc
请告诉我们如何实施这个perl?
答案 0 :(得分:4)
#!/usr/bin/env perl
use strict;
use warnings;
my @list = <DATA>;
my $prev;
for (sort @list) {
next if $prev && $_ eq $prev;
$prev = $_;
print;
}
__DATA__
abc xyz
adc xyz
abc xyz
pqr tyu
xyz abc
tyu pqr
abc pqr
答案 1 :(得分:1)
也许不是生产代码值得,但这是一种方法:
#!/usr/bin/perl
use strict;
use warnings;
my %seen;
print join "",
grep {$_ !~ /^\s+$/ && !$seen{$_}++}
sort {$a !~ /^ user/ <=> $b !~ /^ user/ ||
$a cmp $b} <DATA>;
__DATA__
user1 name user2 name
abc xyz
adc xyz
abc xyz
pqr tyu
xyz abc
tyu pqr
abc pqr
输出:
user1 name user2 name
abc pqr
abc xyz
adc xyz
pqr tyu
tyu pqr
xyz abc
这里最非常规的部分是$a !~ /^ user/ <=> $b !~ /^ user/
排序条件。 $a !~ /^ user/
评估除{1}之外的所有行的1
(true),它将评估为0
(false),因此标题首先放置,尾随行放到第二行排序条件,产生所需的结果。
答案 2 :(得分:1)
这完全取决于您存储数据的方式。我不确定您是否计划存储您的信息,因为您在课堂上可能会或可能没有了解参考资料。例如,如果您不知道引用,则可以执行以下操作:
my @array;
foreach my $value (<INPUT>) {
chomp $value;
my ($user1, $user2) = split (" ", $value);
push (@array, "$user1:$user2");
}
这会将两个值存储为单个字符串。如果不了解参考文献,这是很常见的。
如果您了解参考文献,您可能会这样做:
my @array;
foreach my $value (<INPUT>) {
chomp $value;
my @line = split (" ", $value);
push (@array, \@line);
}
我可以告诉你的是sort子程序允许你创建一个比较和排序值的函数。当您在sort
中使用自己的函数时,会得到两个值$a
和$b
,它们代表您要排序的值。您可以操纵这些,如果-1
小于$a
,则返回$b
或1
如果$ a大于$b
或返回零如果他们都是平等的。 Perl为您提供了两个运算符<=>
和cmp
,使这更容易一些。
我们假设您将值存储为$user1:$user2
,因为您尚未了解引用。您的排序例程可能如下所示。
sub sort {
my ($a_col1, $a_col2) = split (/:/, $a);
my ($b_col1, $b_col2) = split (/:/, $b);
# Now we compare $a to $b. First, we can compare the
# User 1 column:
if ($a_col1 lt $b_col1) {
return -1; #$a < $b
}
elsif ($a_col1 gt $b_col1) {
return 1; #$a > $b
}
# If we're down here, it's because column 1 matches
# for both $a and $b. We'll have to compare column #2
# to see which one is bigger.
if ($a_col2 lt $b_col2) {
return -1; #$a < $b
}
elsif ($a_col2 gt $b_col2) {
return 1; #$a > $b
}
#We're down here because both column #1 and column #2 match for both
#$a and $b. They must be equal
return 0;
}
现在,我的排序看起来像这样:
my @new_array = sort(\&sort, @array);
注意:这不是我个人这样做的方式。我可能会使用内置的cmp
运算符并采用一些快捷方式。但是,我想把它拆分开来,所以你可以理解它。
顺便说一下,如果老师决定你应该在第一列之前对第二列进行排序,你可以通过改变小于和大于周围的符号来轻松修改你的sort
子程序。
这是我的测试程序:
#! /usr/bin/env perl
use strict;
use warnings;
#Putting my data in `@array`
my @array;
foreach my $entry (<DATA>) {
chomp $entry;
my ($user1, $user2) = split " ", $entry;
push @array, "$user1:$user2";
}
# Sorting my data
my @new_array = sort \&sort, @array;
#Now printing out my data nice and sorted...
foreach my $element (@new_array) {
my ($user1, $user2) = split (/:/, $element);
print "$user1\t\t$user2\n";
}
#
# END OF PROGRAM
##################################################
##################################################
# Sort subroutine I'm using to sort the data
#
sub sort {
my ($a_col1, $a_col2) = split (/:/, $a);
my ($b_col1, $b_col2) = split (/:/, $b);
# Now we compare $a to $b. First, we can compare the
# User 1 column:
if ($a_col1 lt $b_col1) {
return -1; #$a < $b
}
elsif ($a_col1 gt $b_col1) {
return 1; #$a > $b
}
# If we're down here, it's because column 1 matches
# for both $a and $b. We'll have to compare column #2
# to see which one is bigger.
if ($a_col2 lt $b_col2) {
return -1; #$a < $b
}
elsif ($a_col2 gt $b_col2) {
return 1; #$a > $b
}
#We're down here because both column #1 and column #2 match for both
#$a and $b. They must be equal
return 0;
}
__DATA__
david fu
david bar
albert foofoo
sandy barbar
albert foobar
答案 3 :(得分:0)
或者它可以如此简单:
print sort <DATA>;
__DATA__
abc xyz
pqr tyu
xyz abc
adc xyz
tyu pqr
abc pqr
abc xyz
但是,只有你的数据如此简单。如果每列中的数据长度不同, 每列必须与最长的项目一样宽。像这样:
__DATA__
abc |xyz |<-- other data in record...
pqrwf |tyu |<-- other data in record...
xyzsder |abc |<-- other data in record...
adca |xyzghrt |<-- other data in record...
tyuvdfcg |pqr |<-- other data in record...
abcvfgfaqrt |pqrbb |<-- other data in record...
abcaaaaaaaaaaa |xyz |<-- other data in record...
在这种情况下,简单排序仍然有效,但请注意,这些列填充了空格而非标签。