我有一份有以下数据的文件-
投入-
A B C D E F
A B B B B B
C A C D E F
A B D E F A
A A A A A F
A B C B B B如果从第2行开始的其他行与第1行有相同的字母,则应该将它们更改为1。基本上,我正在试图找出任何一行与第一行有多相似。
期望输出-
1 1 1 1 1 1
1 1 B B B B
C A 1 1 1 1
1 1 D E F A
1 A A A A 1
1 1 1 B B B第一行已经成为全部1,因为它本身是相同的(很明显)。在第二行中,第一列和第二列与第一行(A B)相同,因此它们成为1 1。其他行也是如此。
我写了下面的代码来完成这个转换-
for seq in {1..1} ; #Iterate over the rows (in this case just row 1)
do
for position in {1..6} ; #Iterate over the columns
do
#Define the letter in the first row with which I'm comparing the rest of the rows
aa=$(awk -v pos=$position -v line=$seq 'NR == line {print $pos}' f)
#If it matches, gsub it to 1
awk -v var=$aa -v pos=$position '{gsub (var, "1", $pos)} 1' f > temp
#Save this intermediate file and now act on this
mv temp f
done
done可以想象,这非常慢,因为嵌套循环非常昂贵。我的真实数据是一个60x10000矩阵,这个程序需要大约两个小时才能在这个矩阵上运行。
我希望你能帮我摆脱内环,这样我就可以在一步内完成所有6个gsubs了。也许把他们放进自己的数组里?我的awk技能还没那么好。
发布于 2017-01-03 17:41:10
输入
$ cat f
A B C D E F
A B B B B B
C A C D E F
A B D E F A
A A A A A F
A B C B B B所需的o/p
$ awk 'FNR==1{split($0,a)}{for(i=1;i<=NF;i++)if (a[i]==$i) $i=1}1' f
1 1 1 1 1 1
1 1 B B B B
C A 1 1 1 1
1 1 D E F A
1 A A A A 1
1 1 1 B B B解释
FNR==1{ .. }当awk读取当前文件的第一次记录时,在大括号内执行操作
拆分(字符串、数组[、字段seps、seps ]) 将字符串划分为由字段seps分隔的部分,并将其存储在数组中,并将分隔字符串存储在seps数组中。
split($0,a)将当前记录或行(
$0)按字段So (defualt,因为我们没有提供第3个参数)分割成块,并将这些片段存储在数组a中,因此数组a包含来自第一行的数据。
a[1] = A
a[2] = B
a[3] = C
a[4] = D
a[5] = E
a[6] = Ffor(i=1;i<=NF;i++)循环遍历每个文件记录的所有字段,直到文件结束。
if (a[i]==$i) $i=1如果第一行的当前索引列值(
i)等于当前行的当前列值,则设置当前列值=1(意思是修改当前列值)
现在我们修改了列值,然后只打印修改过的行
}1
1总是计算为true,它执行默认操作{print $0}。用于对注释的更新请求
同样的问题,我还有一个程序的第二部分,它将行中的数字相加。也就是说,这个输出可以得到6,2,4,2,2,3。您的程序是否可以在这一步中调整以获得这些值?
$ awk 'FNR==1{split($0,a)}{s=0;for(i=1;i<=NF;i++)if(a[i]==$i)s+=$i=1;print $0,s}' f
1 1 1 1 1 1 6
1 1 B B B B 2
C A 1 1 1 1 4
1 1 D E F A 2
1 A A A A 1 2
1 1 1 B B B 3发布于 2017-01-03 17:24:53
您可以使用这个更简单的awk命令来完成这项工作,因为我们避免了shell中的嵌套循环,并且在嵌套循环中重复调用awk:
awk '{for (i=1; i<=NF; i++) {if (NR==1) a[i]=$i; if (a[i]==$i) $i=1} } 1' file
1 1 1 1 1 1
1 1 B B B B
C A 1 1 1 1
1 1 D E F A
1 A A A A 1
1 1 1 B B B编辑:
如下面的注释所示,您可以做些什么来获得每一行中每列的和:
awk '{sum=0; for (i=1; i<=NF; i++) { if (NR==1) a[i]=$i; if (a[i]==$i) $i=1; sum+=$i}
print $0, sum}' file
1 1 1 1 1 1 6
1 1 B B B B 2
C A 1 1 1 1 4
1 1 D E F A 2
1 A A A A 1 2
1 1 1 B B B 3https://stackoverflow.com/questions/41448772
复制相似问题