AWK 查找前 3 个值

AWK 查找前 3 个值

我有一个包含四列的大型数据文件,第四列是该行的总值。我需要能够找到前三列上键入的前三个值。以下 AWK 将生成输出,但当它在数据文件的第四列中发现重复的总计时停止。有人可以指导我如何在这个 AWK 中添加计数器循环,以便它产生正确的输出吗?

BEGIN { FS="," }

{
  site=$1
  region=$2
  town=$3
  totcnt=$4+0

  key=site","region","town

  if (totcnt >=max) {
    max=totcnt
    mytot[key]=max
  }
}

END { for (i in mytot) {print i "," mytot[i]} }

非常感谢

答案1

以下 perl 脚本使用称为数组哈希(或 HoA)的数据结构。散列 (%sites) 具有从前三个字段(站点、区域、城镇)派生的键,散列的每个元素都是一个包含该特定键的所有总数的数组。

它读取每一行以构建 HoA - 剥离任何前导或尾随空白并忽略任何空白行。它还忽略注释(任何以字符开头的内容#),因为它很容易做到,而且我认为能够注释掉文本数据文件中的数据很有用。

脚本读完整个输入文件后,会对属于每个键的数组进行反向排序,然后打印出仅包含每个键的前 3 个值的摘要行。

#!/usr/bin/perl

my %sites=();

while(<>) {
  chomp;
  s/#.*//;        # strip comments #
  s/^\s*|\s*$//g; # strip leading and trailing spaces
  next if (/^$/); # skip blank lines

  my($site,$region,$town,$total) = split /,/;
  my $key = "$site,$region,$town";

  push @{ $sites{$key} }, $total;
}

foreach my $k (sort keys %sites) {
  @{ $sites{$k} } = reverse sort @{ $sites{$k} };
  print $k . ": " . join(", ",@{ $sites{$k}}[0..2] ), "\n";
};

示例输出:

$ ./jon.pl input.txt
site1,North,Bristol: 996776, 9776, 6776
site2,South,Guildford: 99392, 392, 2392
site2,South,London: 99381, 381, 2381
site3,Central,Birmingham: 992628, 5628, 2628
site3,Wales,Cardiff: 99834, 9834, 834
site3,Wales,Swansea: 991796, 3796, 21796
site5,South,Guildford: 99338, 338, 2338
site5,South,London: 99266, 3266, 266
site5,South,Windsor: 99359, 359, 2359
site5,West,Bristol: 997700, 9700, 7700

input.txt包含您提供的样本数据,复制了多次,并在副本中编辑了总计。

可以轻松地将输出修改为更漂亮,或者为每个总计打印一行(提示,循环遍历数组元素 [0..2] 而不是 join() 它们)。


顺便说一句,它可以在 中实现这样的事情awk,但是在 中实现起来要容易得多perl

答案2

要保留三个最大值,您可以使用两个数组,每个数组包含三个元素,一个用于实际值,另一个用于关联键。这些应该保持分类。

BEGIN { FS = "," }

{
    key = sprintf("%s,%s,%s", $1, $2, $3)
    value = $4

    for (i = 1; i <= 3; ++i)
        if (values[i] == "" || values[i] < value) {
            tmp = values[i]
            values[i] = value
            value = tmp

            tmp = keys[i]
            keys[i] = key
            key = tmp
        } else break
}

END {
    for (i = 1; i <= 3; ++i)
        printf("%s,%d\n", keys[i], values[i])
}

这使用两个数组,values并且keys。对于每个读取值 ( value = $4),都会检查该值针对每个值values看看它是否比它们中的任何一个都大。如果是,则将“当前值”( ) 与和value中的值交换values[i]值在数组中“冒泡”。数组keys与数组保持同步values

测试:

$ cat file
A1,B2,C3,35
A4,B5,C6,607
A7,B8,C9,159
A10,B11,C12,100
A13,B14,C15,116
A16,B17,C18,688
A19,B20,C21,346
A22,B23,C24,277
A25,B26,C27,931
A28,B29,C30,552
A31,B32,C33,605
A34,B35,C36,109
$ awk -f script.awk file
A25,B26,C27,931
A16,B17,C18,688
A4,B5,C6,607

相关内容