Получить общие значения в 2 массивах в сценариях оболочки

У меня есть

array1 = (20,30,40,50)
array2 = (10,20,30,80,100,110,40)

Я должен получить общие значения из этих 2 массивов в моем массиве 3, как:

array3 = (20,30,40) 

в порядке сортировки по возрастанию.

7 ответов

Оболочки и стандартные утилиты Unix хорошо справляются с текстовыми файлами.

В этой области массивами будут текстовые файлы, элементами которых являются строки.

Чтобы найти общую часть между двумя такими массивами, есть стандарт comm команда. comm хотя ожидается сортировка по алфавиту.

Итак, если у вас есть два файла A а также B содержащий элементы этих двух массивов, по одному на строку (что также означает, что элементы массива не могут содержать символы новой строки), вы можете найти пересечение с

comm -12 <(sort A) <(sort B)

Если вы хотите начать с bash массивы (но использование массивов в оболочках - это, как правило, хороший признак того, что вы используете не тот инструмент для своей задачи), вы можете конвертировать туда и обратно между bash массивы и наши текстовые файлы массивы строк с printf '%s\n' и разделение слов:

array_one=(20 30 40 50)
array_two=(10 20 30 80 100 110 40)
IFS=$'\n'; set -f
intersection=($(comm -12 <(
   printf '%s\n' "${array_one[@]}" | sort) <(
   printf '%s\n' "${array_two[@]}" | sort)))

Вы почти наверняка не должны использовать оболочку для этого, так что вот ЕДИНСТВЕННОЕ решение для вашей конкретной проблемы:

awk 'BEGIN{
    split("20,30,40,50",array1,/,/)
    split("10,20,30,80,100,110,40",array2,/,/)

    for (i=1;i in array1;i++)
        for (j=1;j in array2;j++)
            if (array1[i] == array2[j])
                array3[++k] = array1[i]

    for (k=1; k in array3; k++)
        printf "array3[%d] = %d\n",k,array3[k]
}'
array3[1] = 20
array3[2] = 30
array3[3] = 40

и если вы скажете нам, что вы действительно пытаетесь сделать, вы можете получить гораздо больше помощи.

Чистое решение bash с использованием массивов:

#!/bin/bash

array1=(20,30,40,50)
array2=(10,20,30,80,100,110,40)

IFS=,
for i in $array1 $array2;{ ((++tmp[i]));}
for i in ${!tmp[*]};{ [ ${tmp[i]} -gt 1 ] && array3+=($i);}
echo ${array3[*]}

Выход

20 30 40

Как array3 не является ассоциативным массивом, индексы идут в порядке возрастания, используя ${!array[*]} нотации. Если вам нужен список через запятую в качестве входных данных, используйте echo "${array3[*]}",

Может использоваться, если исходные элементы являются целыми числами. Это работает, только если каждый из исходных массивов содержит уникальные числа.

Рассмотрите возможность использования python:

In [6]: array1 = (20,30,40,50)

In [7]: array2 = (10,20,30,80,100,110,40)

In [8]: set(array1) & set(array2)
Out[8]: set([40, 20, 30])

В дополнение к любому из этих хороших ответов кажется, что вы также хотите отсортировать ваш массив (содержащий ответ) в порядке возрастания.

Вы можете сделать это разными способами, в том числе:

readarray array3 <<<"$(printf "%s\n" "${array3[@]}" | sort -n)"

Этот метод также позволяет отфильтровывать повторяющиеся значения:

readarray array3 <<<"$(printf "%s\n" "${array3[@]}" | sort -n | uniq)"

И ради упражнения вот еще один способ его решения:

#!/bin/bash

array1=(20 30 40 50)
array2=(10 20 30 80 100 110 40)
declare -a array3

#sort both arrays
readarray array1 <<<"$(printf "%s\n" "${array1[@]}" | sort -n)"
readarray array2 <<<"$(printf "%s\n" "${array2[@]}" | sort -n)"

# look for values
i2=0
for i1 in ${!array1[@]}; do
    while (( i2 < ${#array2[@]} && ${array1[$i1]} > ${array2[$i2]} )); do (( i2++ )); done
    [[ ${array1[$i1]} == ${array2[$i2]} ]] && array3+=(${array1[$i1]})
done


echo ${array3[@]}

Может быть, вы можете использовать Perl для попытки.

#!/bin/perl
use warnings;
use strict;

my @array1 = (20,30,40,50);
my @array2 = (10,20,30,80,100,110,40);
my @array3 = ();
foreach my $x (@array1) {
    # body...
    if (grep(/$x/, @array2)){
        print "found $x\n";
        @array3=(@array3,$x);
    };
}
print @array3

Вот решение со стандартными инструментами командной строки (sort а также join):

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

join требует сортировки входных данных и не распознает числовой порядок сортировки. Следовательно, я сортирую оба списка в порядке сортировки по умолчанию, присоединяюсь к ним, а затем прибегаю к числовому результату.

Я также предположил, что вы создали массивы действительно как массивы, то есть:

array1=(20 30 40 50)

Я думаю, что остальное более или менее самоочевидно, возможно, с помощью help printf а также man bash,

Другие вопросы по тегам