1

テキストファイルの行を一致する最初のフィールドと一致させるための高速で簡潔な方法は何ですか。

サンプル入力:

a|lorem
b|ipsum
b|dolor
c|sit
d|amet
d|consectetur
e|adipisicing
e|elit

望ましい出力:

b|ipsum
b|dolor
d|amet
d|consectetur
e|adipisicing
e|elit

望ましい出力、代替:

b|ipsum|dolor
d|amet|consectetur
e|adipisicing|elit

これを書く方法はたくさん想像できますが、たとえば sed や awk などを使って行うスマートな方法があるのではないかと思います。私のソース ファイルは約 0.5 GB です。

ここには関連する質問がいくつかあります。たとえば、「awk | フィールドの一致に基づいて行をマージする」ですが、他の質問はメモリにあまりにも多くのコンテンツをロードします。ストリーミング方法が必要です。

4

5 に答える 5

3

固定幅フィールドの場合、次を使用できますuniq

$ uniq -Dw 1 file
b|ipsum
b|dolor
d|amet
d|consectetur
e|adipisicing
e|elit

固定幅のフィールドがない場合は、次の 2 つのawk解決策があります。

awk -F'|' '{a[$1]++;b[$1]=(b[$1])?b[$1]RS$0:$0}END{for(k in a)if(a[k]>1)print b[k]}' file
b|ipsum
b|dolor
d|amet
d|consectetur
e|adipisicing
e|elit

awk -F'|' '{a[$1]++;b[$1]=b[$1]FS$2}END{for(k in a)if(a[k]>1)print k b[k]}' file
b|ipsum|dolor
d|amet|consectetur
e|adipisicing|elit
于 2013-08-28T16:31:33.810 に答える
3

これは、前の行を覚えておくだけでよい方法です(したがって、入力ファイルをソートする必要があります)

awk -F \| '
    $1 == prev_key {print prev_line; matches ++}
    $1 != prev_key {                            
        if (matches) print prev_line
        matches = 0
        prev_key = $1
    }                
    {prev_line = $0}
    END { if (matches) print $0 }
' filename
b|ipsum
b|dolor
d|amet
d|consectetur
e|adipisicing
e|elit

代替出力

awk -F \| '
    $1 == prev_key {
        if (matches == 0) printf "%s", $1 
        printf "%s%s", FS, prev_value
        matches ++
    }             
    $1 != prev_key {
        if (matches) printf "%s%s\n", FS, prev_value
        matches = 0                                 
        prev_key = $1
    }                
    {prev_value = $2}
    END {if (matches) printf "%s%s\n", FS, $2}
' filename
b|ipsum|dolor
d|amet|consectetur
e|adipisicing|elit
于 2013-08-28T16:40:20.530 に答える
1

awk の使用:

awk -F '|' '!($1 in a){a[$1]=$2; next} $1 in a{b[$1]=b[$1] FS a[$1] FS $2}
    END{for(i in b) print i b[i]}' file
d|amet|consectetur
e|adipisicing|elit
b|ipsum|dolor
于 2013-08-28T16:35:15.220 に答える
1

これはうまくいくかもしれません(GNU sed):

sed -r ':a;$!N;s/^(([^|]*\|).*)\n\2/\1|/;ta;/^([^\n|]*\|){2,}/P;D' /file

これは、パターン スペースに 2 行を読み込み、両方の行のキーが同じかどうかを確認します。その場合、2 番目のキーを削除して繰り返します。そうでない場合は、最初の行に 2 つ以上のフィールドが存在するかどうかを確認し、存在する場合はそれを出力してから削除します。それ以外の場合は、最初の行を削除するだけです。

于 2013-08-28T19:49:11.020 に答える