处理文本文件以根据另一列的最大值修改列值

处理文本文件以根据另一列的最大值修改列值

我有一个要修改的文件。有 100 个文件存在相同问题。输入文件如下

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59
                
sample1 .   year    1   1000
sample1 .   week1   20  1001
sample1 .   week2   50  1001
                
sample2 .   year    1   5584
sample2 .   week1   20  5585
sample2 .   week2   100 5585
                
sample3 .   year    1   8125
sample3 .   week1   55  8126
sample3 .   week2   100 8126
                
sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

在上面的文件中,第三列中的“总计”是查找表,其最大值不应超过下面各个样本的任何行。

例如,“sample1”的最大值为 1000,但第三列中的“week1”和“week2”的最大值为“1001”。我发现这种情况仅发生在“week1 和 week2”的几行中,并且始终只比最大值大 1。 “week1”和“week2”行的输出应更新为最大值“1000”。下面的示例输出

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59
                
sample1 .   year    1   1000
sample1 .   week1   20  1000
sample1 .   week2   50  1000
                
sample2 .   year    1   5584
sample2 .   week1   20  5584
sample2 .   week2   100 5584
                
sample3 .   year    1   8125
sample3 .   week1   55  8125
sample3 .   week2   100 8125
                
sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

请为我提供指导,告诉我应该如何进行。我是一名初学者程序员,希望学习。感谢您的帮助

答案1

使用(以前称为 Perl_6)

~$ raku -e 'my @a = slurp.split("\n\n", 2);  print @a[0] ~ "\n\n"; 
            my %h;  for @a.[0].lines() { \%h.push: .words.[0,4] }; 
            for @a[1].lines {
                S/^ (\S+)(.* \s)(\S+) $/{"$0$1"}{ %h{$0} < $2 ?? "%h{$0}" !! "$2" }/.put };'   file.txt

Raku 是 Perl 家族中的一种编程语言,因此它的语法无疑是“Perl 式的”。上面我们将slurp文件一次性全部放入内存,2在第一段之后将文件分成几个部分。该数据存储在@a数组中。包含参考值 ( ) 的第一部分@a[0]将立即print编辑。

%h然后声明一个哈希值。我们@a[0]使用for...迭代顶部摘要段落 ( ) lines。这里,每一行都被分成空格分隔的words.[0,4]第一/第五列作为引用键/值对push添加到哈希中。%h

文件的其余部分 ( ) 通过使用...@a[1]进行迭代,这意味着我们可以分析/修改块中的每一行。使用 Raku 的非破坏性替换习惯用法返回修改后的字符串,我们将输入分为第一(键)列、中间列和最终(值)列。forlinesS///$0$1$2

在替换中,我们只需{"$0$1"}按原样打印即可。然而,对于最后一列,我们可以在大括号内运行代码:使用 Raku 的三元运算符测试 ?? 真的 !! 错误的如果它小于,我们返回%h{$0}(key的关联) ,否则返回原始值 ( ) 。value$2$2

输入示例:

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59

sample1 .   year    1   1000
sample1 .   week1   20  1001
sample1 .   week2   50  1001

sample2 .   year    1   5584
sample2 .   week1   20  5585
sample2 .   week2   100 5585

sample3 .   year    1   8125
sample3 .   week1   55  8126
sample3 .   week2   100 8126

sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

示例输出:

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59

sample1 .   year    1   1000
sample1 .   week1   20  1000
sample1 .   week2   50  1000

sample2 .   year    1   5584
sample2 .   week1   20  5584
sample2 .   week2   100 5584

sample3 .   year    1   8125
sample3 .   week1   55  8125
sample3 .   week2   100 8125

sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

最后,查看中间数据结构通常会很有启发,因此%h哈希如下所示(使用.say for %h.sort;);

sample1 => 1000
sample2 => 5584
sample3 => 8125
sample4 => 59

https://docs.raku.org/syntax/S%2F%2F%2F%20非破坏性%20替换
https://docs.raku.org/language/operators#infix_??_!
https://docs.raku.org/language/regexes
https://raku.org

答案2

一个简单的 Awk 语句:

awk -v OFS='\t' '$3 == "total" {maxval[$1] = $5} $1 in maxval && $5 > maxval[$1] {$5 = maxval[$1]} {print}' input.txt

添加了一些换行符:

awk -v OFS='\t' '
  $3 == "total" {
    maxval[$1] = $5
  }
  $1 in maxval && $5 > maxval[$1] {
    $5 = maxval[$1]
  }
  {print}' input.txt

解释:

首先,根据输入文件中的可变间距,我假设它是原始文本中的制表符分隔文本;看来是的。

默认情况下,Awk 将根据任意数量的相邻制表符或空格来解析以分隔字段。对于这个文件来说这很好。

但我们希望输出保持整齐对齐,默认情况下,如果我们更改某些字段值,Awk 会将该行的所有字段分隔符转换为单个空格。因此,我们将输出字段分隔符(OFS)设置为等于制表符,并带有-v用于设置变量的标志。

对于第三个字段是字符串“total”的行,我们将最大值保存在关联数组中(有时称为“散列”,具体取决于您最熟悉的编程语言)。

如果该行的第一个字段存在于关联数组中,并且第五个字段是更大比存储在数组中的值作为该键的最大值,然后我们更改当前行的第五个字段。

然后我们打印当前行,无论是否修改。

提供的输入的输出:

sample1 100A    total   1       1000
sample2 100A    total   1       5584
sample3 100A    total   1       8125
sample4 100A    total   1       59

sample1 .       year    1       1000
sample1 .       week1   20      1000
sample1 .       week2   50      1000

sample2 .       year    1       5584
sample2 .       week1   20      5584
sample2 .       week2   100     5584

sample3 .       year    1       8125
sample3 .       week1   55      8125
sample3 .       week2   100     8125

sample4 .       year    1       59
sample4 .       week1   10      59
sample4 .       week2   8       59

相关内容