Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare/Difference of two arrays in Bash

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" ) 
like image 675
Kiran Avatar asked Feb 22 '10 17:02

Kiran


People also ask

How do I compare two arrays of arrays?

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.

How do I compare two values in a bash script?

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.

How do you compare two arrays the same?

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.

How do I check if two arrays match?

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.


2 Answers

echo ${Array1[@]} ${Array2[@]} | tr ' ' '\n' | sort | uniq -u 

Output

key10 key7 key8 key9 

You can add sorting if you need

like image 119
Ilya Bystrov Avatar answered Oct 24 '22 08:10

Ilya Bystrov


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.

like image 38
ephemient Avatar answered Oct 24 '22 08:10

ephemient