배열에 중복된 값이 있는지 테스트

배열에 중복된 값이 있는지 테스트

배열에서 중복된 값을 테스트하는 간단한 방법을 찾으려고 합니다. 중복 항목이 있는 특정 행을 식별할 수 있는 것은 좋지만 꼭 필요한 것은 아니지만 중복 항목이 있는지 확인할 수 있는 것이 중요합니다.

몇 가지 숫자가 포함된 배열이 있습니다 $key_array.

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

배열에는 숫자가 여러 개 포함될 수 있으며 그 중 일부는 다른 숫자와 중복될 수 있습니다. 그것들은 단지 정수일 뿐입니다. ( 0예를 들어 a로 시작하는 숫자는 03배열에 전혀 들어가지 않아야 하지만, 그런 경우에는 서로 다른 숫자로 취급하는 것보다 캡처하여 3서로 03중복된 것으로 취급하는 것이 좋습니다.)

이 숫자가 중복되는지 확인해야 합니다. 다른 방법이 없으면 종료 코드를 사용하여 이 작업을 수행할 수 있을 것 같습니다. 내가 원하는 것은 이것이다:

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, 0x1, 1e0, 2-1, $'1\n', ' 1'모두 다른 것으로 간주됨).

답변2

arr정수만 포함되고 0으로 채워진 숫자는 중복으로 간주되어야 한다고 가정하면 (예: 01yes, duplicates 1), 첫 번째 배열의 각 요소를 구문 분석하는 동안 두 번째 배열을 사용하여 "표시된" 값을 유지할 수 있습니다. 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을 반환하고, 중복 항목이 없으면 0이 아닌 값을 반환하는 유틸리티 함수를 도입합니다 .

표준 매개변수 확장은 ${variable+word}이전에 설정된 단어 returnif를 삽입하는 데 사용됩니다. 교체 a[10#$key]되면 return함수 실행이 종료되고 호출자에게 종료 상태 0이 반환되어 중복된 값을 찾았음을 나타냅니다. 인덱스는 " 10#$key기본 10 정수로 해석되는 값"을 의미하며 및 와 같은 키를 동일시할 수 있습니다.$key033

관련 정보