【问题标题】:Find duplicate elements in associative array with non consecutive index在具有非连续索引的关联数组中查找重复元素
【发布时间】:2014-04-27 07:41:53
【问题描述】:

我一般从 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[@]}"

编辑:

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

【问题讨论】:

  • 所以你想要(1 6 10) 输出?
  • @anubhava 0 1 6 10 存储在数组中,是的

标签: bash associative-array


【解决方案1】:

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

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[] 中两个或多个条目的条目。

编辑:使用阿德里安在 cmets 中建议的稍微简单的版本。

【讨论】:

  • 由于bash 中的数组索引是在算术上下文中评估的,并且不会对分配中的扩展执行分词,因此第五行可以缩短为ref[array[i]]=${ref[array[i]]}${ref[array[i]]:+ }$i,这在视觉上可能会更容易一些. PS:很高兴见到你,克利福德。
  • 或者,在测试 [[ "${ref[i]% }" == *" "* ]] 时使用 ref[array[i]]="${ref[array[i]]}$i " 并删除尾随空格,这使得整个事情更容易阅读和理解恕我直言(并且可能更快,因为扩展更少)。
  • @AdrianFrühwirth:嗨!你当然是对的,这稍微简单一些。我现在已经相应地改变了我的答案。
【解决方案2】:

你可以使用:

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")

【讨论】:

    【解决方案3】:

    这是我使用 c 风格的 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  
    

    【讨论】:

      【解决方案4】:

      你的$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)
      

      这会打印出原始数组中任何重复值的索引,全部在一行 - 如果您希望它们在不同的行上,只需在 echo 语句周围加上双引号:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-15
        • 2014-11-12
        • 2018-11-05
        • 2017-08-18
        • 1970-01-01
        • 2017-12-01
        • 2011-09-08
        • 2019-09-30
        相关资源
        最近更新 更多