2017-01-03 80 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