行のすべての列が同じであることを確認するスクリプトを高速化します。

行のすべての列が同じであることを確認するスクリプトを高速化します。

各行のすべての「列」が同じであることを確認してから、同じ要素の1つまたは「no_match」を含む新しいファイルを作成するスクリプトを高速化する必要があります。ファイルはカンマで区切られ、約15,000行で構成され、さまざまな数の「列」が含まれています。

たとえば、

1-69
4-59,4-59,4-59,4-61,4-61,4-61
1-46,1-46
4-59,4-59,4-59,4-61,4-61,4-61
6-1,6-1
5-51,5-51
4-59,4-59

新しいファイルに書き込む:

1-69
no_match
1-46
no_match
6-1
5-51
4-59

2行目と4行目には異なる列が含まれているため、削除します。

次はエレガントなスクリプトからは遠いです。

#!/bin/bash

ind=$1 #file in
num=`wc -l "$ind"|cut -d' ' -f1` #number of lines in 'file in'
echo "alleles" > same_alleles.txt #new file to write to

#loop over every line of 'file in'
for (( i =2; i <= "$num"; i++));do
    #take first column of row being looped over (string to check match of other columns with)
    match=`awk "FNR=="$i" {print}" "$ind"|cut -d, -f1`
    #counts how many matches there are in the looped row
    match_num=`awk "FNR=="$i" {print}" "$ind"|grep -o "$match"|wc -l|cut -d' ' -f1`
    #counts number of commas in each looped row
    comma_num=`awk "FNR=="$i" {print}" "$ind"|grep -o ","|wc -l|cut -d' ' -f1`
    #number of columns in each row
    tot_num=$((comma_num + 1))
    #writes one of the identical elements if all contents of row are identical, or writes "no_match" otherwise
    if [ "$tot_num" == "$match_num" ]; then
            echo $match >> same_alleles.txt
    else
            echo "no_match" >> same_alleles.txt
    fi
done

#END

現在、スクリプトは約15,000行すべてを完了するのに約11分かかります。スピードを上げる方法がよくわかりません(正直に動作させることができることに驚きました)。いつでもキャンセルすればいいようです。以下は、利用可能な100行の小さな抜粋です。

allele
4-39
1-46,1-46,1-46
4-39
4-4,4-4,4-4,4-4
3-23,3-23,3-23
3-21,3-21
4-34,4-34
3-33
4-4,4-4,4-4
4-59,4-59
3-23,3-23,3-23
1-45
1-46,1-46
3-23,3-23,3-23
4-61
1-8
3-7
4-4
4-59,4-59,4-59
1-18,1-18
3-21,3-21
3-23,3-23,3-23
3-23,3-23,3-23
3-30,3-30-3
4-39,4-39
4-61
2-70
4-38-2,4-38-2
1-69,1-69,1-69,1-69,1-69
1-69
4-59,4-59,4-59,4-61,4-61,4-61
1-46,1-46
4-59,4-59,4-59,4-61,4-61,4-61
6-1,6-1
5-51,5-51
4-59,4-59
1-18
3-7
1-69
4-30-4
4-39
1-69
1-69
4-39
3-23,3-23,3-23
4-39
2-5
3-30-3
4-59,4-59,4-59
3-21,3-21
4-59,4-59
3-9
4-59,4-59,4-59
4-31,4-31
1-46,1-46
1-46,1-46,1-46
5-51,5-51
3-48
4-31,4-31
3-7
4-61
4-59,4-59,4-59,4-61,4-61,4-61
4-38-2,4-38-2
3-21,3-21
1-69,1-69,1-69
3-23,3-23,3-23
4-59,4-59
3-48
3-48
1-46,1-46
3-23,3-23,3-23
3-30-3,3-30-3
1-46,1-46,1-46
3-64
3-73,3-73
4-4
1-18
3-7
1-46,1-46
1-3
4-61
2-70
4-59,4-59
5-51,5-51
3-49,3-49
4-4,4-4,4-4
4-31,4-31
1-69
1-69,1-69,1-69
4-39
3-21,3-21
3-33
3-9
3-48
4-59,4-59
4-59,4-59
4-39,4-39
3-21,3-21
1-18

私のスクリプトはこれを完了するのに約7秒かかります。

ベストアンサー1

$ awk -F, '{ for (i=2; i<=NF; ++i) if ($i != $1) { print "no_match"; next } print $1 }' file
1-69
no_match
1-46
no_match
6-1
5-51
4-59

申し訳ありません。あなたのコードを見ていません。あまりにも多くのことが起こっています。ループ本文で同じデータを3回呼び出す場合は、awkこれをより効率的に実行するための別の方法を見つける必要があります。また、あなたが関与している場合は、そのタスクを完了する必要はなく、awk簡単に完了することができますgrep(この場合ではありません)。cutawk

上記のスクリプトは、awk一度に1つのカンマ区切りの行を読み取り、各フィールドを最初のフィールドと比較します。テストが失敗すると、no_match文字列が印刷され、スクリプトは次の行から続行されます。ループが完了すると(不一致が見つからない)、最初のフィールドが印刷されます。

スクリプトとして:

#!/usr/bin/awk -f

BEGIN { FS = "," }

{
    for (i=2; i<=NF; ++i)
        if ($i != $1) {
            print "no_match"
            next
        }

    print $1
}
  • FS-Fコマンドラインのオプションを使用して設定することもできる入力フィールドの区切り記号です。awkこの文字の各行は分割され、フィールドが生成されます。
  • NF現在のレコードのフィールド数(「行の列数」)。
  • $ii変数または定数である可能性がある現在のレコードのi:番目のフィールドを参照します(と同様$1)。

関連:


乾いた多様性:

#!/usr/bin/awk -f

BEGIN { FS = "," }

{
    output = $1

    for (i=2; i<=NF; ++i)
        if ($i != output) {
            output = "no_match"
            break
        }

    print output
}

おすすめ記事