我有大量單獨的文件,每個文件包含六列(行數可能有所不同)。舉個簡單的例子:
1 0 0 0 0 0
0 1 1 1 0 0
我試圖確定我有多少個唯一列(即數字及其順序匹配),在本例中為 3。
有沒有一個簡單的單行程式碼可以做到這一點?我知道將一列與另一列進行比較很容易,但如何找到相同的列?
答案1
您可以使用以下管道來計算唯一列:
$ awk '{for (i=1; i<=NF; ++i) a[i]=a[i]$i; } END { for (i in a) print a[i] }' foo \
| sort -u | wc -l
awk 指令轉置您的輸入,對結果行進行排序,僅保留唯一行 ( -u
),最後對所有(唯一)行(即轉置列)進行計數 ( wc -l
)。
請注意,這NF
是一個內建 awk 變量,並自動設定為目前記錄中的欄位數。$i
引用第 i 個欄位並END
保護後面的區塊,以便在處理所有記錄後執行它。 awk 預設使用空白-非空白欄位分隔。
答案2
(((...))),但是要如何找出相同的欄位呢?
$ printf '%s\n' '1 0 0 0 0 0' '0 1 1 1 0 0' | awk -vSUBSEP='=' '
{ for (i=1; i<NF; i++)
for (j=i+1; j<=NF; j++)
if ($i==$j)
M[i,j]++
}
END{ for (m in M) if (M[m]==NR) print m }'
5=6
2=3
2=4
3=4
對於i<j
每行的所有列,M[i,j]
每當這些列的值相等時就會遞增。因此,M[i,j]==NR
在讀取NR
行之後,讀取的所有行的值都是相同的。
答案3
這個問題讓我很感興趣,我想採用一種我無法確切弄清楚的方法並得到一些很好的幫助在我作為不同的問題發布之後。您可以從我發布的問題中理解我試圖遵循的方法。
對於這個問題,我還有另外 2 個解決方案(其中一個來自格努克的答案是珀爾解決方案和另一個來自 約翰的解決方案與我的解決方案相結合)。
#The variable appended_input will remove spaces/tabs and just append the rows.
#Modify the file name in this line. Here I use inputfile as the filename.
appended_input=$(column -s '\t' inputfile | tr -d '[:space:]') ;
#The array variable will store each column-wise value as an array element.
#I use sort to find the number of unique elements.
array=($(
for ((i=0; i<6; i++))
do
new=${appended_input:$i:1}
for ((j=i+6; j<${#appended_input}; j=j+6))
do
new="$new${appended_input:$j:1}"
done
echo "$new"
done
)) | echo "${array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
測試
我的輸入檔如下。
1 0 0 1 0 0
0 1 1 0 0 0
1 1 1 1 1 0
1 0 0 1 0 1
1 0 0 1 0 1
運行上面的腳本後,我得到的輸出為,
00011 00100 01100 10111
您可以將 awc -w
作為最終管道,並且您將獲得僅 4 的輸出,而不是如上所述的唯一列值。
答案4
下面是一個gawk
解決方案,它使用協進程將每一列提供給 的單獨實例,sha256sum
並報告唯一散列的總數(考慮到散列衝突可能性在sha256sum
統計上不顯著,唯一散列的數量應與唯一列的數量一致)。雖然有些人可能認為這是一種令人震驚的駭客行為,但與其他方法相比,這種方法的一個優點是它不會嘗試連接/轉置數據,因此記憶體效率相對較高。
awk 'BEGIN{for(i=1; i<=6; ++i){s=sprintf("%*s", i+1, ""); a[i]="sha256sum"s}}
{for (i=1; i<=6; ++i) print $i |& a[i]}
END{com= "sort | uniq | wc -l"
for (i=1; i<=6; ++i){close(a[i], "to"); a[i] |& getline x;
close(a[i]); print x | com};
close(com)}' file