Home > front end >  Bash find unique values in array1 not in array2 (and vice-versa)
Bash find unique values in array1 not in array2 (and vice-versa)

Time:06-16

In bash, I know to be able to find the unique values between two arrays can be found by:

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

However, this gives the unique values between BOTH arrays. What if I wanted something about the elements that are unique only to array1 and elements that are unique only to array2? For example:

array1=(1 2 3 4 5)
array2=(2 3 4 5 6)

original_command_output = 1 6
new_command_output1 = 1
new_command_output2 = 6

CodePudding user response:

You could use the comm command.

To get elements unique to the first array:

comm -23  \
    <(printf '%s\n' "${array1[@]}" | sort) \
    <(printf '%s\n' "${array2[@]}" | sort)

and elements unique to the second array:

comm -13  \
    <(printf '%s\n' "${array1[@]}" | sort) \
    <(printf '%s\n' "${array2[@]}" | sort)

Or, more robust, allowing for any character including newlines to be part of the elements, split on the null byte:

comm -z -23  \
    <(printf '%s\0' "${array1[@]}" | sort -z) \
    <(printf '%s\0' "${array2[@]}" | sort -z)

CodePudding user response:

comm is probably the way to go but if you're running bash >= 4 then you can do it with associative arrays:

#!/bin/bash

declare -a array1=(1 2 3 4 5) array2=(2 3 4 5 6)
declare -A uniq1=() uniq2=()

for e in "${array1[@]}"; do uniq1[$e]=; done
for e in "${array2[@]}"; do
    if [[ ${uniq1[$e]-1} ]]
    then
        uniq2[$e]=
    else
        unset "uniq1[$e]"
    fi
done

echo "new_command_output1 = ${!uniq1[*]}"
echo "new_command_output2 = ${!uniq2[*]}"
new_command_output1 = 1
new_command_output2 = 6

CodePudding user response:

Personally I would stick to BASH builtins. This will read each character number in arr1 comparing it to the numbers in arr2. If numbers are ordered differently than it will output those numbers as well as any unique numbers

arr1=(1 2 3 4 5)
arr2=(1 3 2 4)

for i in ${arr1[@]} ; do
        [[ $i == ${arr2[i-1))]} ]] || echo $i
done

output: 2 3 5

If you want to get unique numbers not based on location, you can do this instead:

for i in ${arr1[@]} ; do
        read n <<<${arr2[i-1]}
        [[ ${arr1[@]} =~ $n ]] || echo $i
done

output: 5

  • Related