bash中两个数组的比较/差异
是否有可能采取bash中两个数组的差异。
如果您可以建议我这样做的话,那真的很棒。
代码:
Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )
Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )
Array3 =diff(Array1, Array2)
Array3 ideally should be :
Array3=( "key7" "key8" "key9" "key10" )
感谢你的帮助。
7个解决方案
105 votes
echo ${Array1[@]} ${Array2[@]} | tr ' ' '\n' | sort | uniq -u
输出量
key10
key7
key8
key9
您可以根据需要添加排序
Ilya Bystrov answered 2020-06-23T08:27:10Z
28 votes
如果您严格想要key1 < … < key9 > key10,那么
Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )
Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )
Array3=()
for i in "${Array1[@]}"; do
skip=
for j in "${Array2[@]}"; do
[[ $i == $j ]] && { skip=1; break; }
done
[[ -n $skip ]] || Array3+=("$i")
done
declare -p Array3
关联数组可能会改善运行时,但是我个人不会打扰。 如果要处理足够多的数据,那么shell是错误的工具。
对于像丹尼斯答案这样的对称差异,只要我们对输入和输出进行一点点按摩即可使用现有的工具,例如key1 < … < key9 > key10(因为它们适用于基于行的文件,而不适用于shell变量)。
在这里,我们告诉shell使用换行符将数组连接成一个字符串,并在将key1 < … < key9 > key10中的行读回到数组中时放弃制表符。
$ oldIFS=$IFS IFS=$'\n\t'
$ Array3=($(comm -3
comm: file 1 is not in sorted order
$ IFS=$oldIFS
$ declare -p Array3
declare -a Array3='([0]="key7" [1]="key8" [2]="key9" [3]="key10")'
它之所以抱怨是因为按字典顺序排序为key1 < … < key9 > key10。但是由于两个输入数组的排序方式都相似,因此可以忽略该警告。 您可以使用--nocheck-order摆脱警告,或者,如果不能保证输入数组的顺序和唯一性,则可以在
ephemient answered 2020-06-23T08:26:46Z
15 votes
每当出现一个问题,处理可能无法排序的唯一值时,我的脑子立刻就醒悟。 这是我的看法。
码
#!/bin/bash
diff(){
awk 'BEGIN{RS=ORS=" "}
{NR==FNR?a[$0]++:a[$0]--}
END{for(k in a)if(a[k])print k}'
}
Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )
Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )
Array3=($(diff Array1[@] Array2[@]))
echo ${Array3[@]}
输出量
$ ./diffArray.sh
key10 key7 key8 key9
*注意**:像给出的其他答案一样,如果数组中有重复的键,则它们只会被报告一次; 这可能是或不是您正在寻找的行为。 用于处理该问题的awk代码更加混乱,而且不够干净。
SiegeX answered 2020-06-23T08:27:45Z
6 votes
在Bash 4中:
declare -A temp # associative array
for element in "${Array1[@]}" "${Array2[@]}"
do
((temp[$element]++))
done
for element in "${!temp[@]}"
do
if (( ${temp[$element]} > 1 ))
then
unset "temp[$element]"
fi
done
Array3=(${!temp[@]}) # retrieve the keys as values
编辑:
暂时性指出了潜在的严重错误。 如果一个元素存在于一个数组中且具有一个或多个重复项,而根本不存在于另一个数组中,则该元素将被错误地从唯一值列表中删除。 下面的版本试图解决这种情况。
declare -A temp1 temp2 # associative arrays
for element in "${Array1[@]}"
do
((temp1[$element]++))
done
for element in "${Array2[@]}"
do
((temp2[$element]++))
done
for element in "${!temp1[@]}"
do
if (( ${temp1[$element]} >= 1 && ${temp2[$element]-0} >= 1 ))
then
unset "temp1[$element]" "temp2[$element]"
fi
done
Array3=(${!temp1[@]} ${!temp2[@]})
Dennis Williamson answered 2020-06-23T08:28:14Z
6 votes
将comm和array_intersect作为参数,使用comm来完成工作,并使用mapfile将其放回RESULT数组中:
ARR1=("key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10")
ARR2=("key1" "key2" "key3" "key4" "key5" "key6")
mapfile -t RESULT < \
)
echo "${RESULT[@]}" # outputs "key10 key7 key8 key9"
请注意,结果可能不符合源顺序。
额外的奖励,“这就是您在这里的目的”:
function array_diff {
eval local ARR1=\(\"\${$2[@]}\"\)
eval local ARR2=\(\"\${$3[@]}\"\)
local IFS=$'\n'
mapfile -t $1 <
}
# usage:
array_diff RESULT ARR1 ARR2
echo "${RESULT[@]}" # outputs "key10 key7 key8 key9"
在处理bash中传递的数组参数中,使用那些棘手的评估是最糟糕的选择。
另外,请查看comm的联机帮助页; 根据此代码,它很容易实现,例如array_intersect:只需使用-12作为comm选项。
Alex Offshore answered 2020-06-23T08:28:52Z
3 votes
也可以使用正则表达式(基于另一个答案:bash中的数组交集):
list1=( 1 2 3 4 6 7 8 9 10 11 12)
list2=( 1 2 3 5 6 8 9 11 )
l2=" ${list2[*]} " # add framing blanks
for item in ${list1[@]}; do
if ! [[ $l2 =~ " $item " ]] ; then # use $item as regexp
result+=($item)
fi
done
echo ${result[@]}:
结果:
$ bash diff-arrays.sh
4 7 10 12
Denis Gois answered 2020-06-23T08:29:16Z
2 votes
Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )
Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )
Array3=( "key1" "key2" "key3" "key4" "key5" "key6" "key11" )
a1=${Array1[@]};a2=${Array2[@]}; a3=${Array3[@]}
diff(){
a1="$1"
a2="$2"
awk -va1="$a1" -va2="$a2" '
BEGIN{
m= split(a1, A1," ")
n= split(a2, t," ")
for(i=1;i<=n;i++) { A2[t[i]] }
for (i=1;i<=m;i++){
if( ! (A1[i] in A2) ){
printf A1[i]" "
}
}
}'
}
Array4=( $(diff "$a1" "$a2") ) #compare a1 against a2
echo "Array4: ${Array4[@]}"
Array4=( $(diff "$a3" "$a1") ) #compare a3 against a1
echo "Array4: ${Array4[@]}"
输出
$ ./shell.sh
Array4: key7 key8 key9 key10
Array4: key11
ghostdog74 answered 2020-06-23T08:29:36Z