3

私はこのようなフラットファイルを持っています

cat file

ID1, VALUE1_1
ID1, VALUE1_2
ID1, VALUE1_3
ID2, VALUE2_1
ID2, VALUE2_1
ID3, VALUE3_1
ID3...

データ サンプルからわかるように、ID ごとに、その ID にはいくつかの値があり、それらは同じかどうかに関係なく、どのような値でもかまいません。私にとって、それがどの値を拾っているのかは気にしません。どんな値でも機能します。

したがって、各 ID から 1 つの値のみが必要です。どちらでもかまいませんが、どちらかを選ばなければならない場合は、最も長い行を選択します。

ID1, VALUE1_2
ID2, VALUE2_1
ID3, VALUE3_1

それはPythonで行われるかもしれませんが、シェル自体でそれを行う簡単な方法はありますか?私はsedまたはawkを使用できますが、awkコードの段落全体を書かないでください..

次のようになります。

# Pseudo code
# sort -k 1 file | uniq (max(length) by id)  

どうもありがとう !!

4

3 に答える 3

3

編集:

こんにちはuser84771さん

だから私はあなたが言ったことに基づいて私の答えを完全に作り直しました。さらにいくつかの行がありますが、これがあなたが探しているものであることを願っています:

Mysql の group by と同様に、「各 ID」から最大の行を見つけるには、次のようにします。

次のテキスト ファイルがあるとします。

[root@dev7 ~]# cat stackoverflow2.log 
ID1, fdsgfdsggfdsgsdfg
ID1, fdsgsdfg
ID1, fdsgfdgdsfgdsgsdfgdgffdsgfsdg
ID1, fdsgsdfg
ID2, fdgsfdsgfdshshdsfhdfghdsfhdfhdshsdfhsfdh
ID2, fsfgsdgf
ID3, fdgfdgdgfdggfdg
[root@dev7 ~]# 

私は次のことをします:

_DATAFILE=stackoverflow2.log
_KEYS=$(awk '{ $1=$1; print $1}' ${_DATAFILE} | uniq | sed "s,\,,,g" | xargs )
_LARGEST_PER_KEY=""
echo $_KEYS
for i in ${_KEYS}; do
  _LARGEST_PER_KEY="${_LARGEST_PER_KEY}\n$(grep "$i" ${_DATAFILE} | uniq | awk '{ print length ":", $0 }' | sort -n -u | tail -1 | cut -d ":" -f2 | awk '{ $1=$1; print}')"
done;
echo -e ${_LARGEST_PER_KEY}

何が起こっているのかを説明する。

  • _DATAFILE - この変数は入力ファイルです。
  • _KEYS - この変数は、最初の列内のすべてのキーを返します (uniq および関連付けられたデータなしで並べ替えられた)。xargs を使用して、次のステップのためにすべてのキーが一直線になるようにしました。

[root@dev7 ~]# _KEYS=$(awk '{ $1=$1; print $1}' ${_DATAFILE} | uniq | sed "s,\,,,g" | xargs )

[root@dev7 ~]# echo $_KEYS

ID1 ID2 ID3

  • _LARGEST_PER_KEY - この変数は、完了時に結果に使用されます。ここで for ループの前に定義します。

  • for ループは、クエストのキー (例: ID1 ) の grep を実行し、コードのフォーム行を実行して、どれが最長のデータ値を含むかを判断し、数値/一意の並べ替えを実行して、どれが最大かを確認します。tail を使用してその値を取得し、_LARGEST_PER_KEY 文字列に追加します。(注: \n 文字を区切り文字として追加します)

  • for ループが終了したら、echo -e を使用して結果をエコーアウトし、改行文字が画面上で正しく評価されるようにします。

[root@dev7 ~]# echo -e ${_LARGEST_PER_KEY}

ID1、fdsgfdgdsfgdsgsdfgdgffdsgfsdg

ID2、fdgsfdsgfdshshdsfhdfghdsfhdfhdshsdfhsfdh

ID3、fdgfdgdgfdggfdg

注: 最初にすべてを並べ替えたので、再度並べ替える必要はありません。

明確化のためのメモ:

awk '{ $1=$1; print}' - これにより、末尾の空白が削除されます (行頭 / 行末)

uniq - 重複を取り除きます

awk '{ print length ":", $0 }' - 各行の行の長さを取得し、「行の長さ」で出力します:「行テスト」

sort -n -u - 数値ソート (最大数が最後の項目です)。また、データファイルがソートされずに到着した場合、ファイル全体が一意にソートされるようにします。先端 グレンをありがとう。

tail -1 - 最大の行から最後の行を取得します

cut -d ":" -f2 - 正確な行のみが必要な場合は、行の長さを取り除き、単に行を返します

awk '{ $1=$1; print}' - これにより、末尾の空白が削除されます (行頭 / 行末)

繰り返しますが、これを行うにはもう少し効率的な方法があると確信していますが、これが私が思いついたものです。お役に立てれば!

于 2013-08-07T18:17:42.823 に答える
2

これにより、各 ID の最初の行が見つかります。

awk -F, '!seen[$1]++' file

説明:

  • awk 連想配列は事前に宣言する必要がないため、ID が最初に検出されたときseen[$1]は値がゼロになります (数値コンテキストの場合)。
  • seen[$1]++ 連想配列要素を事後インクリメントするため、式は ID が最初に検出されたときにゼロに評価され、それ以外のときには何らかの正の整数に評価されます。
  • awk は 0 を false として扱い、それ以外の数字を true として扱うため、!演算子でポストインクリメント式を否定します。これで、ID が初めて表示されたときにのみ真の式が得られます。!seen[$1]++
  • awk プログラムは次のようになりcondition1 {body1} condition2 {body2} ...ます。
    • は、対応するが true と評価されbodyた場合にのみ実行されます。condition
    • 条件が存在するが本文が省略されている場合、デフォルトのアクションは{print}
    • 本文が存在するが条件が省略されている場合、デフォルトの条件は true と評価され、すべてのレコードに対してアクションが実行されます。

要約すると、この awk プログラムは、式が true と評価されるたびに現在のレコードを出力します。これは、ID が最初に表示されたときだけです。


各 ID の最長の行が本当に必要な場合:

awk '
    length($2) > max[$1] {max[$1] = length($2); line[$1] = $0}
    END {for (id in line) {print line[id]}}
' file

これにより、ID の順序がシャッフルされる場合があります (連想配列は順序付けされていないコレクションです)。sort問題がある場合は、いつでもパイプできます。

于 2013-08-07T18:51:29.170 に答える
1

このawkスクリプトは、ファイルがソートされていると仮定して、あなたが望むことをするはずです:

 awk 'prev!=$1{print}{prev=$1}' datafile

テスト:

$ cat datafile
ID1, VALUE1_1
ID1, VALUE1_2
ID1, VALUE1_3
ID2, VALUE2_1
ID2, VALUE2_1
ID3, VALUE3_1
$  awk 'prev!=$1{print}{prev=$1}' datafile
ID1, VALUE1_1
ID2, VALUE2_1
ID3, VALUE3_1

説明:

  • そのprev!=$1{print}部分は、変数prevがレコードの最初のフィールドとは異なる値を持っている場合、行を出力することを意味します
  • この{prev=$1}部分の意味: 変数 prev をレコードの最初のフィールドの値に設定します。

デフォルトでは、フィールドは空白で区切られ (-Fオプションが使用されていない場合)、レコードは改行で区切られます。

于 2013-08-07T18:21:13.253 に答える