各行のすべての「列」が同じであることを確認してから、同じ要素の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
(この場合ではありません)。cut
awk
上記のスクリプトは、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
現在のレコードのフィールド数(「行の列数」)。$i
i
変数または定数である可能性がある現在のレコードの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
}
答え2
Awkは完全なプログラミング言語です。あなたはすでにそれを使用しています。ただし、1回の回線に複数の呼び出しを持つ単純な操作には使用しないでください。 awkではフィールド区切り文字を使用し、cutを使用しないでください。 awkで処理を完了します。
awk -F',' '
{
eq=1;
for (i = 2; i <= NF; i++)
if ($1 != $i)
eq=0;
print eq ? $1 : "no_match";
}
' $1
答え3
perl を使用してList::MoreUtils
スカラーコンテキスト内のdistinct
/要素を評価します。uniq
perl -MList::MoreUtils=distinct -F, -lne '
print( (distinct @F) > 1 ? "no_match" : $F[0])
' example
1-69
no_match
1-46
no_match
6-1
5-51
4-59
答え4
次のようにエディタを使用してこれを実行することもできますsed
。
sed -e '
s/^\([^,]*\)\(,\1\)*$/\1/;t
s/.*/NOMATCH/
' input.csv
regex
ここでは、それ自体を掛けて行の終わりに達することに頼っています。可能であれば最初のフィールドで終了し、そうでない場合はフラッシュで終了してくださいNOMATCH
。
説明する:
このpbmを見たとき、このような考えが浮かび上がりました。 as
のさまざまな色を考えてみてくださいcomma-separated fields
。stones
彼らは最初の石の繰り返しで前にカンマを付けて行を立てることができると想像してください。
それは次のとおりです。
STONEA ,STONEA ,STONEA ,STONEA ... all the way to end of line
今正規表現で表現すると、次のようになります。
^ (STONEA) (,\1) (,\1) (,\1) ... all the way to end of line
^ (STONEA) (,\1)* $
出力:
1-69
NOMATCH
1-46
NOMATCH
6-1
5-51
4-59