4

How do we compare two arrays and display the result in a shell script?

Suppose we have two arrays as below:

list1=( 10 20 30 40 50 60 90 100 101 102 103 104)
list2=( 10 20 30 40 50 60 70 80 90 100 )

My requirement is to compare these two arrays in an order that it will only display the result as (101 102 103 104) from list1. It should not include the values 70 and 80 which are present in list2 but not in list1.

This does not help since it is including everything:

echo "${list1[@]}" "${list2[@]}" | tr ' ' '\n' | sort | uniq -u

I tried something like this below, but why is it not working?

list1=( 10 20 30 40 50 60 70 90 100 101 102 103 104)
list2=( 10 20 30 40 50 60 70 80 90 100 )

for (( i=0; i<${#list1[@]}; i++ )); do
for (( j=0; j<${#list2[@]}; j++ )); do
     if [[ ${list1[@]} == ${list2[@] ]]; then
         echo 0
         break
             if [[  ${#list2[@]} == ${#list1[@]-1} && ${list1[@]} != ${list2[@]} ]];then
             echo ${list3[$i]}
         fi
     fi
done
done
0

3 Answers 3

5

You can use comm for this:

readarray -t unique < <(
    comm -23 \
        <(printf '%s\n' "${list1[@]}" | sort) \
        <(printf '%s\n' "${list2[@]}" | sort)
)

resulting in

$ declare -p unique
declare -a unique=([0]="101" [1]="102" [2]="103" [3]="104")

or, to get your desired format,

$ printf '(%s)\n' "${unique[*]}"
(101 102 103 104)

comm -23 takes two sorted files (using sort here) and prints every line that is unique to the first one; process substitution is used to feed the lists into comm.

Then, readarray reads the output and puts each line into an element of the unique array. (Notice that this requires Bash.)


Your attempt failed, among other things, because you were trying to compare multiple elements in a single comparison:

[[ ${list1[@]} != ${list2[@]} ]]

expands to

[[ 10 20 30 40 50 60 90 100 101 102 103 104 != 10 20 30 40 50 60 70 80 90 100 ]]

and Bash complains about a binary operator expected instead of the second element, 20.

Sign up to request clarification or add additional context in comments.

Comments

0

Could also use this kind of approach

#!/bin/ksh

list1=( 10 20 30 40 50 60 90 100 101 102 103 104 )
list2=( 10 20 30 40 50 60 70 80 90 100 )

# Creating a temp array with index being the same as the values in list1

for i in ${list1[*]}; do
        list3[$i]=$i
done

# If value of list2 can be found in list3 forget this value

for j in ${list2[*]}; do
        if [[ $j -eq ${list3[$j]} ]]; then
                unset list3[$j]
        fi
done

# Print the remaining values

print ${list3[*]}

Output is

101 102 103 104

Hope it could help

EDIT

In case of the 2 list are the same :

# Print the remaining values

if [[ ${#list3[*]} -eq 0 ]]; then
        print "No differences between the list"
else
        print ${list3[*]}
fi

5 Comments

Thank you.. This perfectly works for my purpose. But when I'm trying to handle a exception it not responding well. if [[ -n ${list3} ]]; then real_val=$(echo 0) else real_val=$(echo "${list3[@]}") fi echo $real_val
What kind of exception ?
-z too not working. Tried with both list3[@] or list3[*] in if clause. Any suggestion how this can be handled ?
suppose in list1 & list2 both the array contains same value then the array output will be null. So, what Im trying to do is - if the array returns null the it will display 0.
Thank you again.. its working.. Looks like the arithmetic comparison yield the actual result.
0

associative arrays are handy for this:

list1=( 10 20 30 40 50 60 90 100 101 102 103 104)
list2=( 10 20 30 40 50 60 70 80 90 100 )
typeset -a onlyList1
typeset -A inList2
for elem in "${list2[@]}"; do inList2["$elem"]=1; done
for elem in "${list1[@]}"; do [[ -v inList2["$elem"] ]] || onlyList1+=("$elem"); done
typeset -p onlyList1
typeset -a onlyList1=(101 102 103 104)

Or similarly, start with all of list1 and remove what's in list2:

typeset -A inList1
for elem in "${list1[@]}"; do inList1["$elem"]=1; done
for elem in "${list2[@]}"; do unset inList1["$elem"]; done
onlyList1=( "${!inList1[@]}" )

1 Comment

Thank your for your input, but this is not working in my environment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.