
行で一意のソートを実行する方法を提案できますか?私は次の情報を持っています:
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
。-l
RS
tonewline
とORS
toも設定されますnewline
。-a
FS
各レコードは選択に基づいて自動的に単語に分割されます-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