按第一行中的字段排序两行,然后按第二行的长度排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了按第一行中的字段排序两行,然后按第二行的长度排序相关的知识,希望对你有一定的参考价值。

我想过滤一个具有以下格式的文件:

Name1|Name2|Name3  
ACGRTIDKEBDIVNRDIVFDOCDDIC  
Name4|Name5|Name6  
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP  
Name1|Name7|Name3 
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ

产量

Name1|Name7|Name3  
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ  
Name1|Name2|Name3  
ACGRTIDKEBDIVNRDIVFDOCDDIC  
Name4|Name5|Name6  
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

我按照第一个名称对文件进行排序,并将第1行和第2行放在一起;但我也希望只留下最长的第二行(这里是留置权1和2,删除第3和第4行)。

我能够使用awk按名称排序:

awk '{if ((NR%1-2)==0) {line=sprintf("%-30s", $0)} else {print line ":" $0}}' file | sort -t '|' -k1 | tr ':' '
' > newfile

我不知道如何按第二行的长度排序(仅保留)(使用sort -n)?

谢谢

答案

Perl解决方案:

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

my %by_length;
my ($id, $l1);

while (<>) {
    ( sub { $by_length{$id} = {l1 => $l1, l2 => $_}
                if length > length($by_length{$id}{l2} // "")
      },
      sub { $id = (split /|/)[0]; $l1 = $_ }
    )[$. % 2]->()
}
print @{ $by_length{$_} }{qw{ l1 l2 }} for sort keys %by_length;

哈希值%by_lengthl2子项中存储每个名称的最长行,以及l1下的相应第一行。

另一答案

复杂的awk + sort解决方案:

awk 'NR % 2 == 0{ sub(/|/, " ", r); print length, r, $0 }{ r = $0 }' file 
| sort -k2,2 -k1,1nr | awk '{ print $2"|"$3 ORS $NF }'

输出:

Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name1|Name2|Name3
ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

奖金解决方案(额外要求):

awk 'NR % 2 == 0{ sub(/|/, " ", r); print length, r, $0 }{ r = $0 }' file 
| sort -k2,2 -k1,1nr | awk '!a[$2]++{ print $2"|"$3 ORS $NF }'

输出:

Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
另一答案

以下是如何在不必将整个文件存储在内存中的情况下轻松自如地执行操作:

1)将每对线折叠为1并添加要排序的键:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file
Name1 28 Name1|Name2|Name3   ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4 52 Name4|Name5|Name6   AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP
Name1 37 Name1|Name7|Name3  AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ

2)按照您喜欢的顺序对上述输出进行排序:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file |
    sort -k1,1 -k2,2nr
Name1 37 Name1|Name7|Name3  AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name1 28 Name1|Name2|Name3   ACGRTIDKEBDIVNRDIVFDOCDDIC
Name4 52 Name4|Name5|Name6   AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

3)保持每个主键值的第一次出现:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file |
    sort -k1,1 -k2,2nr |
    awk '!seen[$1]++'
Name1 37 Name1|Name7|Name3  AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4 52 Name4|Name5|Name6   AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

4)删除步骤1中添加的额外字段,重新分成2行分区,并打印结果:

$ awk -F'|' 'NR%2{n=$1; h=$0; next} {print n, length(), h, $0}' file |
    sort -k1,1 -k2,2nr |
    awk '!seen[$1]++{print $3 ORS $4}'
Name1|Name7|Name3
AGRQHUOQGRINQJIOPQPJGREQPJIRPEQJIRPEQ
Name4|Name5|Name6
AFFHJORJOVFDANJFOONKFANIFNIPNIPNFIPNKFPDNBKFPNBKFP

如果空白字符不适合您作为组合字段的分隔符,则只需选择一个不同的字符(例如制表符或控制字符或......)。

以上是关于按第一行中的字段排序两行,然后按第二行的长度排序的主要内容,如果未能解决你的问题,请参考以下文章

MYSQL先按第一个字段排序,若相同再按第二个字段排序,如何实现?

按第二个值对元组列表进行排序,reverse=True,然后按 key,reverse=False

具有两个标题行的表排序器

orderByChild() 如果值相同,如何按第二个变量排序?

如何按第二个单词对列表进行排序? [复制]

如何按第一位数字的降序对整数数组进行排序? [关闭]