UNIXでのディープ検索拡張

UNIXでのディープ検索拡張

私のファイルには、ユーザーと監督者の関係を持つ次のデータがあります。

user |supervisor |id
-----|-----------|----
a    |   b       | 1
b    |   c       | 2
c    |   d       | 3
e    |   b       | 4

以下のように、ユーザーと監督者の関係階層を分析したいと思います。

user |supervisor |id
-----|-----------|----
a    |   b       | 1
a    |   c       | 1
a    |   d       | 1
b    |   c       | 2
b    |   d       | 2  
c    |   d       | 3
e    |   b       | 4
e    |   c       | 4
e    |   d       | 4 

ご覧のとおり、ユーザー「a」の場合、直属の監督者は「b」ですが、「b」は再び「c」を彼の監督者として持っています。したがって、間接的に「c」は「a」の監督者でもあります。たとえば、私の目標は、特定のユーザーの階層のすべてのレベルを分析することです。 Unixでこの機能を実装する最良の方法は何ですか?

答え1

各ユーザーが入力ファイル(「ユーザー」列)に一度だけ表示されるとします。また、パイプ(|)区切り文字が実際にファイル内にあり、常に空白でデータと区切られ、ヘッダー行が次のように見なされます。いいえ実際に存在します。

これが使用された2段階のソリューションですawk。最初のステップでは、各人の監督者を含む配列を作成し、2番目のステップでは出力を作成します。

awk 'pass==1 { super[$1] = $3; }
     pass==2 {
                print
                user=$3
                while (super[user] != "") {
                        print $1, "|", super[user], "|", $5
                        user=super[user]
                }
             }
    ' pass=1 data pass=2 data

これにより、正しく整列されていない出力が生成されます。この問題を解決するにはパイプしてくださいcolumn -t。あるいはawk、必要に応じてスクリプトで出力形式を指定することもできます。

しかし、これは一般的です転移的閉鎖

答え2

複雑アッ解決策:

awk 'NR<3{ h=(h=="")? $0 : h ORS $0 }NR>2{ uid[$1]=$5; us[$1]=$3 }
     END{ 
         print h; 
         for (u in uid) { 
             id=uid[u]; spvr=us[u]; printf("%-5s|%-11s|%-4s\n",u,spvr,id); 
             while (spvr in uid) { 
                 spvr=us[spvr]; printf("%-5s|%-11s|%-4s\n",u,spvr,id) 
             } 
         }
     }' yourfile

出力:

user |supervisor |id
-----|-----------|----
a    |b          |1   
a    |c          |1   
a    |d          |1   
b    |c          |2   
b    |d          |2   
c    |d          |3   
e    |b          |4   
e    |c          |4   
e    |d          |4 

詳細:

  • NR<3{ h=(h=="")? $0 : h ORS $0 }- キャプチャヘッダーワイヤー

  • uid[$1]=$5-ユーザーIDリレーショナル配列

  • us[$1]=$3-ユーザー監督者リレーショナル配列

  • spvr=us[u]- 1位家庭教師現在のためにユーザー

  • while (spvr in uid) { ... }- しかし家庭教師にありますユーザーリスト、親のインポート家庭教師

答え3

私のawkソリューション(RomanPerekhrestの出力形式を使用)デフォルトでは、2つの関連ループがあります。まず、ユーザーの新しいスーパーバイザーを操作する場合は、そのスーパーバイザーのすべての依存関係(つまり、スーパーバイザーチェーン)をそのユーザーに追加する必要があります。次に、2番目のループは、現在処理されているユーザーを依存関係として持つ他のすべてのユーザーを見つけ、現在のユーザーのすべての依存関係をここに追加します。

#!/usr/bin/awk
# file process_it.awk
BEGIN {

    FS="|";
}

NR<3 {

    h=(h==""? $0 : h ORS $0)
}

NR>2 {

   gsub(/ /, "", $0)
   curr_user=$1;
   curr_supervisor=$2;
   curr_id=$3;
   print curr_user, curr_supervisor;
   arr[curr_user][curr_supervisor]++;
   id[curr_user]=curr_id;

   if(isarray(arr[curr_supervisor])) {
       for(sub_indx in arr[curr_supervisor])
           arr[curr_user][sub_indx]++;
    }
    else
        delete arr[curr_supervisor];

    for(indx in arr) {

        if(isarray(arr[indx])) {

            for(sub_indx in arr[indx]) {

                if(sub_indx==curr_user) {

                    for(sub_indx2 in arr[curr_user])
                    arr[indx][sub_indx2]++;
                }
            }    
        }
    }
}

END {
    print h;

    for(i in arr) {

        if(isarray(arr[i])) {

            for(j in arr[i])
                printf "%-5s|%-11s|%-3s\n", i, j, id[i];
        }
    }
}

使用:

awk -f process_it.awk your_file.txt

関連情報