Comparing two sorted arrays

Let's say I have the following 2 arrays. Arrays are always sorted alphabetically.

arr1=(abc) arr2=(abcd) 

I need to compare these two arrays, and if they exactly match, then true should be returned.

+6
source share
4 answers

I got a possible solution for you using STDIN and diff:

 #!/bin/bash arr1=(abc) arr2=(abcd) diff=$(diff <(printf "%s\n" "${arr1[@]}") <(printf "%s\n" "${arr2[@]}")) if [[ -z "$diff" ]]; then echo "TRUE" else echo "FALSE" fi 

EDIT: A little explanation:

It outputs a string from your arrays and passes them as diff via STDIN. diff either returns the difference or nothing that I enter into the variable and test with -z for the content later.

+9
source

Since "$*" takes all positional parameters as a single word, this can be done:

 [ "${arr1[*]}" == "${arr2[*]}" ] && echo "equal" || echo "distinct" 

Note that the expression [ condition ] && echo "equal" || echo "distinct" [ condition ] && echo "equal" || echo "distinct" equivalent

 if [ condition ]; then echo "equal" else echo "distinct" fi 

Test

 $ arr1=(abc) $ arr2=(abcd) $ [ "${arr1[*]}" == "${arr2[*]}" ] && echo "equal" || echo "distinct" distinct $ arr2=(abc) $ [ "${arr1[*]}" == "${arr2[*]}" ] && echo "equal" || echo "distinct" equal 

It just works 100% if there are elements without spaces (see discussion in the comments).

+7
source

The most reliable way I can think of is by:

  • first compare the dimensions of the array
  • item by item

So:

 arr1=(1 2 3 ) arr2=(1 2 "3 4") [ ${#arr1[*]} != ${#arr2[*]} ] && { echo arrays different size; exit 1; } for ii in ${!arr1[*]}; do [ "${arr1[$ii]}" == "${arr2[$ii]}" ] || { echo different element $ii; exit 1; } done echo arrays identical exit 0 

Used constructions:

  • ${#array[*]} , which returns the number of elements in the array
  • ${!array[*]} , which returns a list of indexes (and not ${array[*]} , which returns elements)

The above should handle spaces within the values ​​of an array, sparse arrays and associative arrays (although it does not always catch different indexes in associative arrays, you will need an additional test for this).

+3
source

For those of you who want to get a solution using a function instead of checking directly, here is the solution I wrote. The latter works with regular arrays, associative arrays, and sparse arrays. But this requires at least Bash 4.3.

This function is part of the lib I wrote. As a symbol in my library, I use return values ​​and the global retval argument for return statements that are more complex than a prime. The same applies to errorWithLog , which is just an echo on stderr and is logged as an error for the system logger, if the latter is available.

 #------------------------------------------------------------------------------- # I: - The array to compare tableA[@] # - The second array tableB[@] against which to compare the first array # P: Search if both arrays (all types) are equal # NOTE: The tables must be passed *AS NAME* as myTable not as $myTable[@] # nor ${myTable[@]} and requires Bash 4.3 # Inspired from http://stackoverflow.com/a/17990637/3514658 # and from http://stackoverflow.com/a/4017175/3514658 # O: - If both arrays are equal: # - retval: true # - return value for direct usage in a if statement: 0 # - If both arrays are not equal: # - retval: false # - return value for direct usage in a if statement: 1 #------------------------------------------------------------------------------- function isArraysEqual() { # Accessing by dereference using -n is new in Bash 4.3. local -n arr1=$1 2>/dev/null local -n arr2=$2 2>/dev/null # If <Bash 4.3, need to use the following syntax, but checking the keys of # associative arrays is not supported and, in that case, tables must be # passed as names *WITH* elements ie: myTable[@] # local -a arr1=("${!1}") # local -a arr2=("${!2}") if [ $? -ne 0 ]; then errorWithLog "isArraysEqual() accessing using dereference with -n"\ "needs at least Bash 4.3. Arrays reported as different." retval=false return 1 fi # Check size first. This is way faster than checking each item over # iteration. if [ ${#arr1[@]} != ${#arr2[@]} ]; then retval=false return 1 fi # The ! expands to a list of array keys. For normal arrays, not associative # arrays, this gives a list of index values starting from 0. local -a arr1Keys=("${!arr1[@]}") local -a arr2Keys=("${!arr2[@]}") for (( i = 0; i < ${#arr1[@]}; i += 1 )); do key=${arr1Keys[$i]} # Check if the values are the same. If the key does not exist in arr2 # and the key does exist but is null in arr1, the values are NOT # considered different. This is why checking keys is mandatory. if [ "${arr1[$key]}" != "${arr2[$key]}" ]; then retval=false return 1 fi # Check if keys are the same. This is needed for associative arrays. if [ "${arr1Keys[$i]}" != "${arr2Keys[$i]}" ]; then retval=false return 1 fi done retval=true return 0 } 

Examples of using:


 declare -A table1=([hello]=world [ab]=cd) declare -A table2=([hello]=world [ab]=cd) if isArraysEqual table1[@] table2[@]; then echo "yes" else echo "no" fi 

Gives yes .


 declare -A table1=([hello]=world [ab]=cd) declare -A table2=([hello]=world [ab]=cde) if isArraysEqual table1 table2; then echo "yes" else echo "no" fi 

Gives no .


 declare -A table1=([hello]=world [abhe]=ce) declare -A table2=([hello]=world [ab he]=ce) if isArraysEqual table1 table2; then echo "yes" else echo "no" fi 

Gives no .


 table1=(1 2 3 4) table2=(1 2 "3 4") if isArraysEqual table1 table2; then echo "yes" else echo "no" fi 

Gives no .

+2
source

Source: https://habr.com/ru/post/950799/


All Articles