gpt4 book ai didi

perl - 在Perl中按三列用自定义条件对逗号分隔的文件进行排序

转载 作者:行者123 更新时间:2023-12-02 09:04:26 25 4
gpt4 key购买 nike

我有一个逗号分隔的文本文件。我想首先按第三列,然后第二列,然后第一列对文件进行排序。

但是,我希望第3列按字母顺序排序,最长的值在前。

例如,依次为AAA,AA,A,BBB,BB,B,CCC,CC,依此类推。

输入(alpha-sort-test2.txt):

JOHN,1,A
MARY,3,AA
FRED,5,BBB
SAM,7,A
JOHN,3,AAA
JOHN,2,AAA
BETTY,2,AAA
JARROD,7,AAA
JOANNE,2,BB
AMANDA,2,DD
AMY,5,B
PETE,7,CC
MATT,4,B
SARAH,3,CCC
GEORGE,3,CC
AMANDA,3,AAA

到目前为止,我拥有的Perl代码如下:
$infile = "alpha-sort-test2.txt";
$outfile = "alpha-sort-test-sorted2.txt";

open (INFILE, "<$infile") or die "Could not open file $infile $!";
open (OUTFILE, ">$outfile");

my @array = sort howtosort <INFILE>;

foreach (@array)
{
chomp;
print "$_\n";
print OUTFILE "$_\n";
}

sub howtosort
{
my @flds_a = split(/,/, $a);
my @flds_b = split(/,/, $b);

$flds_a[2] cmp $flds_b[2];
}

close INFILE;
close OUTFILE;

当前输出(alpha-sort-test-sorted2.txt):
JOHN,1,A
SAM,7,A
MARY,3,AA
AMANDA,3,AAA
JOHN,3,AAA
JOHN,2,AAA
BETTY,2,AAA
JARROD,7,AAA
AMY,5,B
MATT,4,B
JOANNE,2,BB
FRED,5,BBB
PETE,7,CC
GEORGE,3,CC
SARAH,3,CCC
AMANDA,2,DD

所需的输出:
BETTY,2,AAA
JOHN,2,AAA
AMANDA,3,AAA
JOHN,3,AAA
JARROD,7,AAA
MARY,3,AA
JOHN,1,A
SAM,7,A
FRED,5,BBB
JOANNE,2,BB
MATT,4,B
AMY,5,B
SARAH,3,CCC
GEORGE,3,CC
PETE,7,CC
AMANDA,2,DD

提前致谢。

最佳答案

第三领域的标准有些复杂。

词法比较是逐个字符进行的,因此abc小于ax,但更长的字符串更大,其他所有条件都相等。因此,ab小于b,但ab大于a

因此,对第三个字段的要求将这两件事混合在一起,并在中间中断了cmp。如果我们要使用cmp,则abb之前(正确),但是aaa之后(不需要)。我根本看不到如何针对此需求使用cmp

因此,对于这些条件,这是一个非常基本的实现

use warnings;
use strict;
use feature 'say';
use Path::Tiny qw(path); # convenience

my $file = shift // die "Usage: $0 file\n";
my @lines = path($file)->lines({ chomp => 1 });

my @sorted =
map { $_->[0] }
sort { custom_sort($a, $b) }
map { [$_, split /,/] }
@lines;

say for @sorted;


sub custom_sort {
my ($aa, $bb) = @_;

# Last field for both terms, their lengths
my ($af, $bf) = map { $_->[-1] } $aa, $bb;
my ($len_a, $len_b) = map { length } $af, $bf;

# Strip and return first characters and compare them lexicographically
# Then compare lengths of original strings if needed
# Keep going until difference is found or one string is depleted
while (
(my $ca = substr $af, 0, 1, "") and
(my $cb = substr $bf, 0, 1, "") )
{
if ($ca gt $cb) {
return 1
}
elsif ($ca lt $cb) {
return -1;
}
elsif ($len_a < $len_b) {
return 1
}
elsif ($len_a > $len_b) {
return -1
}
}

# Still here, so third field was the same; use other two criteria
return
$aa->[2] <=> $bb->[2]
||
$aa->[1] cmp $bb->[1];
}

这将打印出所需的列表。

一些评论
  • 在调用sort之前,我们首先形成一个arrayref,包括整个字符串及其各个字段,这样以后就不必在每次比较时都将字符串拆分了。这是Schwartzian transform
  • 第三字段的标准:按字母顺序比较每个字符,直到找到差异为止;如果一个字符串包含在另一个字符串中,则较长者获胜。因此,abcab的逐字符比较在babc'wins'
  • 处停止
  • substr中的(可选)第四个参数是对返回的子字符串的替换,该字符串在第二个和第三个参数中找到。因此,这里用空字符串替换以0开头的一个长子字符串-它将删除并返回第一个字符。这就像在数组
  • 上使用 shift一样
  • 如果第三个字段完全相同,则对第二个字段进行数字比较;如果它们相同,则按字母顺序比较第一个字段
  • 比较之后,我们从排序后的arrayrefs
  • 中检索原始字符串

    关于perl - 在Perl中按三列用自定义条件对逗号分隔的文件进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60163272/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com