2017-01-03 46 views
4

我有以下DATA-gsub多列同时基于不同的gsub条件?

输入 -

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。等其他行。

我写了下面的代码执行此transformation-

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的矩阵,它需要大约2个小时才能运行该程序。

我希望你能帮我摆脱内部循环,这样我就可以一步完成所有6个gsub。也许把它们放在他们自己的数组中?我的awk技能还没那么好。

+1

请看看:我该怎么办时,有人回答我的问题?(http://stackoverflow.com/help/someone-answers) – Cyrus

回答

3

输入

$ 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读取当前文件的第一个记录,做的事情在大括号

分裂(字符串,阵列[,fieldsep [,SEPS]])

除以字符串转换成由fieldsep分隔件和将数组 存储在数组中,并将分隔符字符串存储在seps数组中。

  • split($0,a)

分割当前记录或行($0)到由fieldsep件(defualt空间, 我们还没有提供第三参数),并存储在阵列a 件所以阵列a包含来自第一行的数据

 a[1] = A 
     a[2] = B 
     a[3] = C 
     a[4] = D 
     a[5] = E 
     a[6] = F 
  • for(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 
+0

这很好用,并且和@anubhava的解决方案一样快。 +1。 – VM17

+0

@VarunM很高兴知道。 –

+0

同样的问题在这里,我有一个程序的第二部分,将行中的数字相加。即你会得到6,2,4,2,2,3这个输出。您的程序是否可以调整,以在这一步本身获得这些值? – VM17

4

你可以使用这个简单的awk命令做这将是更快的任务来完成,因为我们避免了在外壳嵌套循环,并在嵌套循环中重复调用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 3 
+1

''++为简单起见! – Inian

+1

,我相信它的速度更快:) – Cyrus

+0

这个工程就像一个魅力。使我的整体计划速度提高了3.5倍。 我有程序的第二部分,将行中的数字相加。即你会得到6,2,4,2,2,3这个输出。您的程序是否可以调整,以在这一步本身获得这些值?我应该问这是一个单独的问题吗? – VM17