行内で一意に並べ替え

行内で一意に並べ替え

行で一意のソートを実行する方法を提案できますか?私は次の情報を持っています:

Special   c1,c2,c5,c7,c1,c2   
Special2  C6

Special(これはとの間のタブ文字ですc1...。)

私は次の出力が欲しい:

Special   c1,c2,c5,c7  
Special2  C6

どうすればいいですか?

答え1

使用この回答

perl -MList::MoreUtils=uniq -laF'\t' -ne '
    $F[1] = join(",", uniq(sort(split(",", $F[1])))); print join("\t", @F)'

外部パッケージによって異なります。リスト::追加ユーティリティ。外部依存関係をインストールしたくない場合は、uniq機能を再実装することをお勧めします。Perlコード数行。 (macOSベースシステムの一部としてインストールされているようですが)

答え2

perl -F'\t|,' -lane 'my %h; print shift @F, "\t", join ",", sort grep !$h{$_}++, @F' dataf

説明する

  • -F'\t|,'@F=>各レコードフィールドをTABまたは文字配列に分割しますcomma
  • -lRStonewlineORStoも設定されますnewline
  • -aFS各レコードは選択に基づいて自動的に単語に分割されます-F
  • -nループ読み取りの暗黙的な記録が入力に設定され、要求されたANDときにのみ内容を印刷します。
  • -e上記の選択に従ってPerl各入力レコードに対して実行されるコード。RS-l
  • 最初の要素が提供され、shift残りの要素はレコードが読み取られるたびに再生成されるハッシュuniquifiedのキーとして保存されます。%h次に、一意の要素を並べ替え、カンマで連結して印刷します。

答え3

OpenBSD awk、GNU、および以下を使用してawkテストされましたmawk

awk -F ',| +' '{ for (i = 2; i <= NF; ++i) { print $1, $i } }' data.in |
sort -u |
awk '{ f[$1] = (f[$1] ? f[$1] "," : "") $2 } END { for (k in f) { print k, f[k] } }'

最初は、awk与えられたデータを次に拡張します。

Special c1
Special c2
Special c5
Special c7
Special c1
Special c2
Special2 C6

カンマと複数のスペースをフィールド区切り文字として使用し、入力された各レコード(行)に対して最初のフィールドを別々の行に順次印刷し、他のすべてのフィールドを順次印刷します。これは、区切り文字として正しく解釈される位置に加えて、行に余分なスペースやカンマがないと仮定します。

中央は次sortのように並べ替えます。

Special2 C6
Special c1
Special c2
Special c5
Special c7

行全体をソートキーとしてソートし、重複行を削除します。

最後に、awkデータは次のように再組み立てされます。

Special c1,c2,c5,c7
Special2 C6

最初のフィールドを連想配列のキーとして使用し、データをコンマで区切って2番目のフィールドに関連付けて値として保存することによってこれを行います。最後に収集されたすべてのデータを印刷します。

答え4

もう一つの方法は1行です。

while read line; do echo "$line" | awk '{print $1}' | tr '\n' ' ';  echo "$line" | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',' | sed -e 's/.$//g'; echo; done < file_to_sort

各行の最初の列()を取得し、2番目の列のecho $line | awk '{print $1}' | tr '\n' ' ';値を「、」で区切って適用用の単一列に変換し、元のsort形式()の単一行に戻しますecho $line | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ','

@tripleeeが提案したように行分割を実行します。

while IFS=$'\t' read first second; do printf "%s\t%s\n" "$first" "$(tr ',' '\n' <<<"$second" | sort | tr '\n' ',' | sed -e 's/.$//g';)"; done < file_to_sort

関連情報