Сравнение двух разных массивов с помощью сценария оболочки - PullRequest
0 голосов
/ 25 сентября 2018

Как мы сравниваем два массива и отображаем результат в сценарии оболочки?

Предположим, у нас есть два массива, как показано ниже:

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

Мне необходимо сравнить эти два массива впорядок, в котором результат будет отображаться только как (101 102 103 104) из list1.Он не должен включать значения 70 и 80, которые присутствуют в list2, но отсутствуют в list1.

Это не помогает, поскольку включает все:

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

Я попробовал что-то подобное ниже, но почему это не работает?

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

Ответы [ 3 ]

0 голосов
/ 25 сентября 2018

удобны для этого ассоциативные массивы:

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)

Или, аналогично, начните со всего list1 и удалите то, что есть в list2:

typeset -A inList1
for elem in "${list1[@]}"; do inList1["$elem"]=1; done
for elem in "${list2[@]}"; do unset inList1["$elem"]; done
onlyList1=( "${!inList1[@]}" )
0 голосов
/ 25 сентября 2018

Можно также использовать этот подход

#!/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[*]}

Вывод

101 102 103 104

Надеюсь, что это может помочь

РЕДАКТИРОВАТЬ

В случае2 списка одинаковы:

# Print the remaining values

if [[ ${#list3[*]} -eq 0 ]]; then
        print "No differences between the list"
else
        print ${list3[*]}
fi
0 голосов
/ 25 сентября 2018

Вы можете использовать comm для этого:

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

, что приводит к

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

или, чтобы получить желаемый формат,

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

comm -23 берет два отсортированных файла (здесь используется sort) и печатает каждую строку, уникальную для первой; процесс подстановки используется для подачи списков в comm.

Затем readarray считывает выходные данные и помещает каждую строку в элемент unique массив.(Обратите внимание, что для этого требуется Bash.)


Ваша попытка не удалась, среди прочего, потому что вы пытались сравнить несколько элементов в одном сравнении:

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

расширяется до

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

и Bash жалуется на бинарный оператор, ожидаемый вместо второго элемента, 20.

...