在非关联索引的关联数组中查找重复元素

时间:2014-03-20 12:40:35

标签: bash associative-array

我从一般的bash和代码开始并且有很多痛苦要写这个,有人能告诉我它是否适用于所有情况请,也许有人有更好的方法? 非常感谢提前。

array=( [0]=24 [1]=24 [5]=10 [6]=24 [10]=24 [12]=12 )
KEYS=(${!array[@]})

for i in "${!KEYS[@]}"; do

    for j in "${!KEYS[@]}"; do

    if [[ $i -eq $j ]]; then
        continue
    fi

    if [[ ${array[${KEYS[$i]}]} -eq ${array[${KEYS[$j]}]} ]]; then

        duplicate+=( ${KEYS[$j]} )
    fi
    done

done

uniq=($(printf "%s\n" "${duplicate[@]}" | sort -u)); 

echo "${uniq[@]}"

编辑:

我的预期输出是一个包含重复元素索引的数组。

4 个答案:

答案 0 :(得分:4)

这种方法具有线性复杂度(假设恒定时间数组查找)而不是级联循环的二次复杂度:

array=( [0]=24 [1]=24 [5]=10 [6]=24 [10]=24 [12]=12 )
ref=( )

for i in "${!array[@]}"; do
    ref[array[i]]="${ref[array[i]]}$i "
done

for i in "${!ref[@]}"; do
    [[ "${ref[i]% }" == *" "* ]] && echo "$i @ ${ref[i]% }"
done

第一个循环将数据从array[]复制到ref[],切换键和值的角色,并在发生冲突时连接新值(各个条目之间有空白)。因此,在第一个循环ref[]之后将具有以下内容:

ref=( [10]="5 " [12]="12 " [24]="0 1 6 10 " )

第二个循环打印来自ref[]的条目,但跳过所有不包含空白的条目,不包括尾随空白,因此只打印那些指向array[]中两个或更多条目的条目。

编辑:使用Adrian在评论中建议的稍微简单的版本。

答案 1 :(得分:2)

你的$KEYS数组是什么?您将$array的索引存储在其中,但之后您只用于引用这些索引 - 这是不必要的。这是一个与原始帖子相同但没有$KEYS的脚本:

array=( [0]=24 [1]=24 [5]=10 [6]=24 [10]=24 [12]=12 )

for i in "${!array[@]}"; do
    for j in "${!array[@]}"; do
        [ "$i" -eq "$j" ] && continue
        [ "${array[$i]}" -eq "${array[$j]}" ] && duplicate+=("$j")
    done
done

echo $(printf "%s\n" "${duplicate[@]}" | sort -u)

这打印出原始数组中任何重复值的 indices ,全部在一行 - 如果你想在不同的行上,只需在echo语句周围加上双引号:

echo "$(printf "%s\n" "${duplicate[@]}" | sort -u)"

答案 2 :(得分:1)

这是我使用c-style for循环的方法,最后将打印数组中所有重复的数字。

arr=( 1 2 3 4 5 6 1 2 3 4 5 6 0 1 3 )
repeats=()

for (( i=0; i < ${#arr[@]}; ++i )); do
   for (( j=i+1; j < ${#arr[@]}; ++j )); do
       if [ ${arr[i]} -eq ${arr[j]} ]; then
           repeats+=( ${arr[i]} )
            break
       fi  
   done
done

echo ${repeats[@]} | grep -o . | sort -u  

答案 3 :(得分:1)

您可以使用:

uarr=($(for i in "${!array[@]}";do echo $i ${array[$i]}; done|awk 'a[$2]++{printf "%s ",$1}'))

给出了:

set | grep uarr
uarr=([0]="1" [1]="6" [2]="10")