配列に重複した値があるかどうかをテストする

配列に重複した値があるかどうかをテストする

配列で重複した値をテストする簡単な方法を見つけようとしています。重複項目がある特定の行を識別できることは良いですが、必須ではありませんが、重複項目があるかどうかを確認できることが重要です。

いくつかの数字を含む配列があります$key_array

# echo ${key_array[@]}
1 2 3 4 3 3

配列には複数の数字を含めることができ、その一部は他の数字と重複する可能性があります。それらは単なる整数です。 (0たとえば、aで始まる数字は配列にまったく入ってはいけませんが、そのよう03な場合は、異なる数字として扱うよりもキャプチャして、重複したものとして扱うことをお勧めします。)303

この番号が重複していることを確認する必要があります。他の方法がなければ、終了コードを使用してこれを行うことができるようです。私が望むのはこれです:

if $(some command); then
 echo "Array contains duplicates."
 exit 1
fi
$(commands to run after duplicate check)

最終的なアイデアは、重複がある場合、スクリプトがユーザーに通知して終了することです(重複がどこにあるかを識別することはそれほど重要ではなく、ユーザーに重複を確認するように指示するだけで十分です)。継続的に実行され、他の多くのタスクも実行されます。

どうすればこれを行うことができますか?

答え1

zshシェルから:

array=(1 2 3 4 3 3)
if (($#array != ${#${(u)array}})); then
  print -u2 array contains duplicates
  exit 1
fi

ここでは${(u)array}配列の固有要素に拡張されるので、要素数と固有要素数を比較するだけです。

シェルにはbashそれに対応するものはありませんが、配列にはNULバイトを含めることができないため、GNUシステムを使用している場合は次のことができます。

readarray -td '' dups < <(
  (( ${#array[@]} == 0 )) ||
    printf '%s\0' "${array[@]}" |
      LC_ALL=C sort -z |
      LC_ALL=C uniq -zd
)

if ((${#dups[@]} > 0)); then
  echo >&2 "array has duplicates:"
  printf >&2 ' - "%s"\n' "${dups[@]}"
  exit 1
fi

要素が考慮される場所コピーバイト単位で同じ場合、数値(存在する場合)が同じ場合ではありません(、、、、、、、、すべて1が異なる01と見なされます)。0x11e02-1$'1\n'' 1'

答え2

arr整数のみが含まれ、ゼロで埋められた数字は重複と見なされる必要があると仮定すると(例:01yes、duplicates 1)、最初の配列の各要素を解析するときに2番目の配列を使用して「表示された」値を保持できます。arr

#!/bin/bash
arr=(1 2 3 4 3 3)
seen=()

for i in "${arr[@]}"; do
    #Remove padding zeroes, if any
    i=$((10#$i))
    # If element of arr is not in seen, add it as a key to seen
    if [ -z "${seen[i]}" ]; then
        seen[i]=1
    else
        echo "Array contains a duplicate."
        break
    fi
done

答え3

Bash 3.Xで動作するには、次のものを使用できますuniq

IFS=$'\n' sort <<<"${key_array[*]}" | uniq -d; unset IFS

これにより、配列内のすべての重複要素のみが返され、返されます。

説明する

  1. IFS=$'\n'設定内部フィールド区切り記号新しい行文字に変換して、"${key_array[*]}"各配列要素が新しい行に拡張されるようにします。
  2. <<<ここにある文字列の出力をの"${key_array[*]}"標準入力に供給しますsort
  3. sortわかりました、まとめました。
  4. uniq -d出力 "...入力で繰り返される各行の単一コピー。man uniq"
  5. unset IFSはいビジネスが良いをクリックしてIFSデフォルトにリセットします。

答え4

配列に整数(正の整数)のみが含まれていると仮定すると、key_array通常の配列は次のような事実を使用できます。足りないbashシェルに。次のコードは、すでに処理されたキーが見つかるまで通常の配列の要素をインスタンス化するときにキー配列を繰り返します。

key_array=( '09' 1 2 3 4 3 3 '04' '001' '07' )

has_dupes () (
        unset -v a

        for key do
                ${a[10#$key]+'return'}  # execute "return" if a[10#$key] is set
                a[10#$key]=             # set a[10#$key] to empty string
        done

        return 1
)

if has_dupes "${key_array[@]}"; then
        echo 'array has dupes'
else
        echo 'array has no dupes'
fi

has_dupesこれは整数リストを取得し、リストに重複項目がある場合は0を返し、重複項目がない場合はゼロ以外の値を返すユーティリティ関数を導入します。

標準パラメータ拡張は、${variable+word}以前に設定された単語returnifを挿入するために使用されます。交換するa[10#$key]return、関数の実行が終了し、呼び出し側に終了ステータス0が返され、重複した値が見つかったことを示します。インデックスは「10#$key基本10整数として解釈される値」を意味し、 と同じキーを同一視できます。$key033

関連情報