我有一个包含多个列(以逗号分隔)的文件,其中值重复。我想要做的是合并或者#34;汇总"基于这些列的行。
例如,假设我有以下内容:
输入文件:
ID, Name , Eye Color, Hair Color, Marital Status
1 , John , Brown , Brown , Single
1 , Mary , Green , Brown , Married
2 , Joe , Blue , Blonde , Divorced
2 , Brian, Green , Brown , Single
2 , Gary , Brown , Blonde , Married
我想要基于第一和第四列的以下输出:
输出文件:
ID, Name , Eye Color, Hair Color, Marital Status, Name, Eye Color, Hair Color, Marital Status
1 , John , Brown , Brown , Single , Mary, Green , Brown , Married
2 , Joe , Blue , Blonde , Divorced , Gary, Brown , Blonde , Married
2 , Brian, Green , Brown , Single
我可以使用以下awk为第一列执行此操作:
awk -F, '
NR!=1 && p1!=$1 { print prev; prev="" }
{ p1=$1; prev=(prev"") ? prev FS substr($0,index($0,$2)) : $0 }
END { if(prev"") print prev }
' input.txt > output.txt
我还需要找到一种方法来包含第四列。
答案 0 :(得分:2)
这里是一般的想法,不假设记录是有序的(但也不保留顺序)
$ awk 'BEGIN{ FS=" *, *"; OFS=","}
NR==1{split($0,header);next}
{a[$1,$4]=(($1,$4) in a?a[$1,$4] OFS:"") $0}
END{for(k in a) print a[k]}' file
2 , Joe , Blue , Blonde , Divorced,2 , Gary , Brown , Blonde , Married
2 , Brian, Green , Brown , Single
1 , John , Brown , Brown , Single,1 , Mary , Green , Brown , Married
您可以像在逻辑中那样过滤不需要的重复列,并且需要使标头符合匹配记录的最大长度......
带扩展标头的格式化版本可以是
$ awk 'BEGIN{FS=" *, *"; OFS=","}
NR==1{$1=$1; header0=$0; split($0,header); next}
{$1=$1; c[$1,$4]++;
a[$1,$4]=(($1,$4) in a?a[$1,$4] OFS $2 OFS $3 OFS $5:$0)}
END{for(k in c) if(max<c[k]) max=c[k];
printf "%s",header0;
for(i=2;i<=max;i++) printf "%s", OFS header[2] OFS header[3] OFS header[5];
print "";
for(k in a) print a[k] | "sort -n" }' file |
column -ts,
ID Name Eye Color Hair Color Marital Status Name Eye Color Marital Status
1 John Brown Brown Single Mary Green Married
2 Brian Green Brown Single
2 Joe Blue Blonde Divorced Gary Brown Married
答案 1 :(得分:0)
以下使用三个关联数组来跟踪所有内容......
x
数组是一个二维&#34;交叉引用&#34; - 具有第1列和第4列值的索引,并且存储值是我们将找到匹配行的行号。g
数组会跟踪我们&#34;成长的次数。一排特别的。 (我们使用此数组在需要时增加标题。)o
数组是我们的输出数组,用于聚合我们的数据行。我们使用sprintf
重新格式化输入的最后一列,然后再附加到输出,以根据问题的输出要求保留表格的间距。
awk -F, -v OFS=, '
($1, $4) in x {
# existent row -- append
i = x[$1, $4]
$1 = ""
$5 = sprintf("%-15s", $5)
o[i] = o[i] $0
if(++g[i] > g[1]) {
# grow the header row
o[1] = o[1] h
++g[1]
}
next
}
{
# new output row
x[$1, $4] = ++n
$5 = sprintf("%-15s", $5)
o[n] = $0
}
NR==1 {
# save header for append
$1 = ""
h = $0
}
END {
for (i=1; i<=n; ++i)
print o[i]
}'
输出是问题中指定的内容(包括顺序和格式)。上述一个可能的缺点是,如果有人有相当复杂的婚姻状况,格式(间隔)可能不会成立。此外,如果尾随空白区域是不可接受的,则可以通过END
在for
区块sub(/ +$/, "", o[i])
循环中轻松删除。