gpt4 book ai didi

AWK:基于现有列创建新列

转载 作者:行者123 更新时间:2023-12-04 13:08:01 24 4
gpt4 key购买 nike

下面是我的文件的样子(按 $3 排序):

name_1|G1026|2017-08-27|2017-08-27|2017-09-02|19|19|21
name_2|G1566|2018-05-05|2018-05-05|2018-06-11|51|51|2B
name_2|G2124|2018-06-11|2018-06-11|2018-06-11|51|19|2B
name_2|G2125|2018-06-11|2018-06-11|2018-06-15|51|19|41
name_1|G4391|2020-08-14|2020-08-14|2020-08-20|19|19|21
name_1|G4392|2020-08-14|2020-08-20|2020-08-20|19|51|21

字段分隔符是| .我正在尝试添加一个额外的列 $9基于现有列添加到此文件。对于 $1 中的多个名称实例,我想应用以下条件:

cond1 && (cond2 || cond3 || cond4) && (!cond5)

prevcur是具有相同第一个字段、非空第三个字段和 cur 的两行以下 prev .第 1、5 或 5、6 行是具有第一个字段 name_1 的此类行对。 .第 2,3 行和第 3,4 行是具有第一个字段 name_2 的此类行对。 .

delta = number-of-days(prev.$5 - cur.$4)是天数prev.$5过去cur.$4 .

条件是:

  1. cond1 = (0 <= delta <= 2 days)

    例如,对于 name_1 的第一个实例(第一行),检查是否prev.$5第一个实例(第一行)在 0 到 2 天后 cur.$4来自第二个实例(第 6 行)。

  2. cond2 = (prev.$6 == 51)

  3. cond3 = (cur.$7 == 51)

  4. cond4 = (cur.$8 == "2B" || cur.$8 == 41)

  5. cond5 = (prev.$6 == 19 && cur.$7 == 51 && cur.$8 == 21)

如果满足这些条件,则添加列 $9到两行中的第一行,因此输出将如下所示。

name_1|G1026|2017-08-27|2017-08-27|2017-09-02|19|19|21
name_2|G1566|2018-05-05|2018-05-05|2018-06-11|51|51|2B|group1
name_2|G2124|2018-06-11|2018-06-11|2018-06-11|51|19|2B|group2
name_2|G2125|2018-06-11|2018-06-11|2018-06-15|51|19|41
name_1|G4391|2020-08-14|2020-08-14|2020-08-20|19|19|21
name_1|G4392|2020-08-14|2020-08-20|2020-08-20|19|51|21

添加的列以group1 开头.每次添加列时,前导数字都会递增。

如果要求prev.$cur.$值在一行中,然后我可以应用以下代码:

awk -F "|" '{if ($1=="name_1" && (($5-$4)<=2) && ($6==51||$7==51||$8==2B|41) &&($6!=19 && $7!=51 && $8!=21)) print $9="group1"}' OFS="|"文件

有关如何使用 awk 解决此问题的任何线索将不胜感激!

最佳答案

以下需要 GNU awk 扩展(mktime):

$ cat foo.awk
function d2ts(d) {
gsub(/-/, " ", d)
return mktime(d " 0 0 0")
}

BEGIN {
f8["2B"] = 1;
f8["41"] = 1;
}

FNR == NR {
if($1 in ts && (f6[$1] == 51 || $7 == 51 || $8 in f8) &&
!(f6[$1] == 19 && $7 == 51 && $8 == 21)) {
delta = ts[$1] - d2ts($4)
if(delta >= -12*3600 && delta <= 60*3600)
change[nr[$1]] = 1
}
ts[$1] = d2ts($5)
f6[$1] = $6
nr[$1] = NR
next
}

{
if(FNR in change)
$(NF+1) = "group" ++cnt
print
}

$ awk -F'|' -f foo.awk OFS='|' file file
name_1|G1026|2017-08-27|2017-08-27|2017-09-02|19|19|21
name_2|G1566|2018-05-05|2018-05-05|2018-06-11|51|51|2B|group1
name_2|G2124|2018-06-11|2018-06-11|2018-06-11|51|19|2B|group2
name_2|G2125|2018-06-11|2018-06-11|2018-06-15|51|19|41
name_1|G4391|2020-08-14|2020-08-14|2020-08-20|19|19|21
name_1|G4392|2020-08-14|2020-08-20|2020-08-20|19|51|21

我们分两个阶段进行,file 被传递两次的原因。第一遍检查所有条件并将要修改的记录编号存储在关联数组 change 中。第二阶段将最后一列添加到所有记录中,该数字是 change 关联数组的键。

Note: in order to account for daylight savings time and leap seconds the date comparison does not use 0 and 2 days thresholds but minus half a day (-12*3600) and 2 days and a half (60*3600). As your date fields have only a 1 day resolution this should behave as expected.

解释:

  • d2ts 函数将 YYYY-MM-DD 日期转换为 UNIX 时间戳,即自 1970/01/01 以来的秒数。这是通过首先使用 gsubYYYY-MM-DD 转换为 YYYY MM DD(空格而不是 -), 连接 0 0 0 表示小时、分钟、秒,然后使用 mktime 转换为 UNIX 时间戳。

  • 由于您的算法引用过去的行,我们使用关联数组(tsf6nr)来存储有关最后遇到的具有给定字段 #1 值的行。键是字段 #1 的值 (name_X),值分别是字段 #5 的 UNIX 时间戳、字段 #6 的值和记录号。

  • 由于字段 #8 有多个候选值,我们在 BEGIN 部分定义了另一个关联数组 (f8),并使用 in 运算符用于测试。

当然,根据您的文件,您可能会在第一阶段遇到内存问题。例如,如果您有数十亿个不同的 name_X 值,则可能需要进行一些调整以避免由于关联数组的大小而导致内存溢出。

关于AWK:基于现有列创建新列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68499930/

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