Is it possible to take the difference of two arrays in Bash. What is a good way to do it?
Code:
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" )
Using Arrays. equals(array1, array2) methods − This method iterates over each value of an array and compare using equals method. Using Arrays. deepEquals(array1, array2) methods − This method iterates over each value of an array and deep compare using any overridden equals method.
echo "enter two numbers"; read a b; echo "a=$a"; echo "b=$b"; if [ $a \> $b ]; then echo "a is greater than b"; else echo "b is greater than a"; fi; The problem is that it compares the number from the first digit on, i.e., 9 is bigger than 10, but 1 is greater than 09.
The Arrays. equals() method checks the equality of the two arrays in terms of size, data, and order of elements. This method will accept the two arrays which need to be compared, and it returns the boolean result true if both the arrays are equal and false if the arrays are not equal.
Check if two arrays are equal or not using SortingSort both the arrays. Then linearly compare elements of both the arrays. If all are equal then return true, else return false.
echo ${Array1[@]} ${Array2[@]} | tr ' ' '\n' | sort | uniq -u
Output
key10 key7 key8 key9
You can add sorting if you need
If you strictly want Array1 - Array2
, then
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
Runtime might be improved with associative arrays, but I personally wouldn't bother. If you're manipulating enough data for that to matter, shell is the wrong tool.
For a symmetric difference like Dennis's answer, existing tools like comm
work, as long as we massage the input and output a bit (since they work on line-based files, not shell variables).
Here, we tell the shell to use newlines to join the array into a single string, and discard tabs when reading lines from comm
back into an array.
$ oldIFS=$IFS IFS=$'\n\t' $ Array3=($(comm -3 <(echo "${Array1[*]}") <(echo "${Array2[*]}"))) comm: file 1 is not in sorted order $ IFS=$oldIFS $ declare -p Array3 declare -a Array3='([0]="key7" [1]="key8" [2]="key9" [3]="key10")'
It complains because, by lexographical sorting, key1 < … < key9 > key10
. But since both input arrays are sorted similarly, it's fine to ignore that warning. You can use --nocheck-order
to get rid of the warning, or add a | sort -u
inside the <(…)
process substitution if you can't guarantee order&uniqueness of the input arrays.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With