文字列「1 2 3 2 1」または配列[1,2,3,2,1]がある場合、どのようにして一意の値を選択できますか。
"1 2 3 2 1" produces "1 2 3"
または
[1,2,3,2,1] produces [1,2,3]
uniqに似ていますが、uniqは行内のパターンではなく、行全体で機能するようです...
文字列「1 2 3 2 1」または配列[1,2,3,2,1]がある場合、どのようにして一意の値を選択できますか。
"1 2 3 2 1" produces "1 2 3"
または
[1,2,3,2,1] produces [1,2,3]
uniqに似ていますが、uniqは行内のパターンではなく、行全体で機能するようです...
回答:
GNUの場合awk(これも元の順序を保持します)
printf '%s\n' "1 2 3 2 1" | awk -v RS='[[:space:]]+' '!a[$0]++{printf "%s%s", $0, RT}'
1 2 3
のreadへのbash配列
read -ra arr<<<$(printf '%s\n' "1 2 3 2 1" |
awk -v RS='[[:space:]]+' '!a[$0]++{printf "%s%s", $0, RT}')
printf "%s\n" "${arr[@]}"
1
2
3
bash配列を意味する場合、方法を追加
zshを使用している場合:
$ array=(1 2 3 2 1)
$ echo ${(u)array[@]}
1 2 3
または(KSH_ARRAYSオプションが設定されていない場合)
$ echo ${(u)array}
1 2 3
"${(u)array[@]}"またはを使用する必要があります"${(@u)array}"(引用符に注意してください)。
${(u)array}、引用符なしで配列が空または空の文字列が含まれている場合でも機能します。
任意の値を持つ配列の場合、bash組み込みの演算子がないため、非常に扱いにくいです。
bash ただし、変数にNUL文字を格納することはサポートされていないため、それを利用して他のコマンドに渡すことができます。
に相当zsh:
new_array=("${(@u}array}")
最近のGNUシステムでは、次のようになります。
eval "new_array=($(
printf "%s\0" "${array[@]}" |
LC_ALL=C sort -zu |
xargs -r0 bash -c 'printf "%q\n" "$@"' sh
))"
または、の最新バージョンではbash、空の配列要素がないと仮定して、連想配列を使用できます。
unset hash
typeset -A hash
for i in "${array[@]}"; do
hash[$i]=
done
new_array=("${!hash[@]}")
bash 4.4以降とGNUの場合sort:
readarray -td '' new_array < <(
printf '%s\0' "${array[@]}" | LC_ALL=C sort -zu)
要素の順序は、これらの異なるソリューションでは同じではありません。
とtcsh:
set -f new_array = ($array:q)
保持なるF(IRST要素a b a=> a b)などzshの(u)拡張フラグ。
set -l new_array = ($array:q)
最後を保持します(a b a=> b a)。ただし、これらは配列から空の要素を削除します。
この解決策は私にとってうまくいきました。
ids=(1 2 3 2 1)
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
上記は1 2 3を出力として生成します。
Costasによって提案された短いバージョンは、
printf "%s\n" "${ids[@]}" | sort -u | tr '\n' ' '
最終結果を配列に格納するには、次のようにします。
IFS=$' '
arr=($(printf "%s\n" "${ids[@]}" | sort -u | tr '\n' ' '))
unset IFS
さて、エコーをオンにするとarr、これが私の出力です。
echo "${arr[@]}"
1 2 3
参考文献
https://stackoverflow.com/a/13648438/1742825 https://stackoverflow.com/a/9449633/1742825
tr '\n' ' '
それを完全にシェルで行い、結果を配列に入れるには、
declare -A seen
for word in one two three two one
do
if [ ! "${seen[$word]}" ]
then
result+=("$word")
seen[$word]=1
fi
done
echo "${result[@]}"
つまり、特定の単語をまだ表示していない場合は、その単語をresult配列に追加して、表示済みとしてフラグを付けます。単語が表示されたら、それ以降の出現は無視してください。
unset seen以前declare -A seenに$seen(環境からのスカラー変数としても)定義されている場合は、以前に必要になることに注意してください。