文字列「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
zshを使用する場合:
$ array=(1 2 3 2 1)
$ echo ${(u)array[@]}
1 2 3
または(KSH_ARRAYS
オプションが設定されていない場合)
$ echo ${(u)array}
1 2 3
答え2
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
答え3
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最初の要素(a b a
=>)は拡張フラグa b
のように動作します。zsh
(u)
set -l new_array = ($array:q)
最後の項目(a b a
=> b a
)が保持されます。ただし、配列から空の要素を削除します。
答え4
全体をシェルで実行し、結果を配列に保存するには、
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
に追加して見たものとしてマークします。単語が表示されたら、後に続く単語を無視してください。