我正在尝试找到一种简单的方法来测试数组中的重复值。能够识别具有重复项的特定行固然很好,但并非完全必要,但重要的一点是能够看到存在重复项。
我有一个数组,$key_array
其中包含一些数字:
# echo ${key_array[@]}
1 2 3 4 3 3
该数组可以有任意数量的数字,其中一些数字可能与其他数字重复。它们只是整数。 (以 a 开头的数字0
,例如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
where${(u)array}
扩展为数组的唯一元素,因此我们只是将元素数与唯一元素数进行比较。
shellbash
没有等效的东西,但由于它的数组无论如何都不能包含 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
仅包含整数并且零填充数字应被视为重复(例如,01
是 的重复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
这将返回且仅返回数组的所有重复元素。
描述
答案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
它接受一个整数列表,如果列表中有重复值则返回零,如果没有重复值则返回非零。
标准参数扩展${variable+word}
用于插入先前设置的单词return
if 。a[10#$key]
当return
被替换时,它终止函数的执行并向调用者返回零退出状态,表示我们发现了重复值。索引的意思是“解释为以 10 为基数的10#$key
整数的值”,并允许我们将键等同起来,例如和。$key
03
3