最初の列と一致する行の場合は、2番目の列を使用して「X参照Y」リストを作成します。

最初の列と一致する行の場合は、2番目の列を使用して「X参照Y」リストを作成します。

ウィキデータの場合は、QuickStatmentsを作成して同じ名前の要塞にP1889値を割り当てたいと思います。これは次のように単純化できます。

次の内容を含むファイルの場合:

Fort George,Q12
Fort George,Q56
Fort George,Q678
Fort Anne,Q3

最初の列で正確な一致を実行し、XがYを見るときに一致するすべてのペアを出力したいと思います。

Q12 see also Q56
Q12 see also Q678
Q56 see also Q12
Q56 see also Q678
Q678 see also Q12
Q678 see also Q56

ファイルは最初の列に基づいてソートされます。これは何か奇妙な問題のように感じますが、執筆をあきらめました。

答え1

使用ミラーmlr)は最初に最初のフィールドに基づいて2番目のフィールドを縮小し(実際にはソートする必要はありません)、縮小された2番目のフィールドを繰り返して文字列の組み合わせを印刷します。

$ mlr --csv -N nest --ivar : -f 2 then put -q 'a = splita($2, ":"); for (i in a) { for (j in a) { i != j { print i . " see also " . j } } }' file
Q12 see also Q56
Q12 see also Q678
Q56 see also Q12
Q56 see also Q678
Q678 see also Q12
Q678 see also Q56

実行後の中間結果はnest次のとおりです。

$ mlr --csv -N nest --ivar : -f 2 file
Fort George,Q12:Q56:Q678
Fort Anne,Q3

このput表現は美しいです。

a = splita($2, ":");

for (i in a) {
    for (j in a) {
        i != j { print i . " see also " . j }
    }
}

同じパターンに従うことができますが、awkまず入力が次のようになると仮定する必要があります。シンプルCSV(つまり、挿入されたカンマや改行などを含まない)はさらに冗長になります。

$ awk -F , '{ d[$1] = d[$1] == "" ? $2 : d[$1] ":" $2 } END { for (k in d) { split(d[k],a,":"); for (i in a) for (j in a) if (i != j) printf "%s see also %s\n", a[i], a[j] } }' file
Q56 see also Q678
Q56 see also Q12
Q678 see also Q56
Q678 see also Q12
Q12 see also Q56
Q12 see also Q678

コードがawk美しく印刷されます。

{
    d[$1] = d[$1] == "" ? $2 : d[$1] ":" $2
}

END {
    for (k in d) {
        split(d[k], a, ":")

        for (i in a) for (j in a)
            if (i != j) printf "%s see also %s\n", a[i], a[j]
    }
}

in連想配列のインデックスにアクセスするためにinを使用しても、特定のawk順序が保証されるわけではありません。順序を変更するには、代わりに算術ループを使用してください。内容が長すぎてここではお見せしません。

答え2

これをサポートするawkを使用し(ほとんどサポートしています)、delete array$ 1の$ 2値を一度に1つずつメモリに保存します。

awk '
    BEGIN { FS=","; OFS=" see also " }
    $1 != prev {
        delete a
        prev = $1
    }
    {
        for ( i in a ) {
            print $2, i ORS i, $2
        }
        a[$2]
    }
' file
Q56 see also Q12
Q12 see also Q56
Q678 see also Q56
Q56 see also Q678
Q678 see also Q12
Q12 see also Q678

delete aあなたのawkがそれをサポートしていない場合新しいawkを入手してくださいしかし、split("",a)どのawkでも使用できます。

sort出力ラインの順序を変えるには、出力を 。

答え3

次のPerlスクリプトはハッシュ配列(「HoA」)データ構造を使用します(参照:perldoc perldscそしてペリリルアルコールおよび関連文書)。

簡単に言うと、「HoA」は、各要素がゼロ個以上のデータ要素を含むインデックス配列を格納する連想配列(別名「ハッシュ」)です(配列は空である可能性があります。この場合、各配列はその後少なくとも1つの要素をあります)。追加する要素がないと生成されません。)

#!/usr/bin/perl

while (<<>>) {
  chomp;
  my @F = split /\s*,\s*/;
  push @{ $a{$F[0]} }, $F[1];
}

foreach my $k (sort keys %a) {
  my @values = @{ $a{$k} };
  foreach my $v1 (@values) {
    foreach my $v2 (@values) {
      print "$v1 see also $v2\n" unless $v1 eq $v2;
    }
  };
};

まず、入力の各行を読み取り、各行の末尾から改行を削除し、行を@Fコンマ配列に分割します(カンマに隣接するか隣接しない可能性があるスペースは無視します)。次に、@Fの最初の要素をaハッシュのキーとして使用し、@F%aの2番目の要素を%aの対応する要素に格納されている配列にプッシュ(つまり追加)します。

すべての入力を読み取るときは、%aのキーを繰り返してから2回繰り返し、そのキー内の配列内の値を入れ子にして、値が異なる場合にのみ行を印刷します。

%aのキーをソートしましたが、必要はありません。 Perlハッシュは本質的に順序がないので(ほとんどの言語のように)出力の一貫性を保証するためのものです。ソートされていない場合は、実行ごとにランダムな順序で表示されます。

@values配列を並べ替えることもできますが、(値は文字と数字の混合なので)自然なソートアルゴリズム(時には「バージョンソート」とも呼ばれます)を実装したり、並べ替え::自然または並べ替え::バ​​ージョンまたは他の自然注文モジュールの1つCPAN。そのまま読み出した順番で値を出力します。

技術的には、@values出力ループの配列は必要ありません。単に@{ $a{$k} }アンループとして使用することもできますが、私の考えでは、この方法が読んで理解しやすくなります。$v1$v2

スクリプトを別の名前で保存して実行可能にしたsee-also.pl後、サンプル入力のサンプル出力chmod

$ ./see-also.pl input.txt 
Q12 see also Q56
Q12 see also Q678
Q56 see also Q12
Q56 see also Q678
Q678 see also Q12
Q678 see also Q56

答え4

また、datamashbash中括弧拡張を使用してデータをグループ化して組み合わせを取得することもできます。たとえば、次のようになります。

<infile datamash -st, --output-delimiter=$'\t' -g1 collapse 2 |
cut -f2                                                       |
while read; do
  bash -c "printf '%s\n' {$REPLY}$'\t'{$REPLY}"
done                                                          |
awk '$1 != $2 { print $1 " see also " $2 }'

関連情報