Удалить массив записей из другого массива

У меня есть 2 массива

    a=(1,2,3,4,5)
    b=(2,4)

выход должен быть

    c=(1,3,5) 

(который должен быть результатом ab)

Я пытался использовать

    unset a[${b}] 

есть идеи?

то, что я работаю сейчас, это цикл, который проходит через 700000 итераций

5 ответов

Решение

Прежде всего, если вы хотите сделать это за 700000 итераций, вам действительно следует заняться чем-то другим, кроме bash. Кроме того, то, что вы показываете, это не массив в bash, а строка1. Массивы разделяются пробелами, а не запятыми.

Тем не менее, вот способ bash, предполагающий истинные массивы:

a=(1 2 3 4 5)
b=(2 4)
c=( $(printf "%s\n" "${a[@]}" "${b[@]}" | sort | uniq -u) )

Если у вас есть строки, разделенные запятыми, а не массивы, используйте вместо этого:

a=(1,2,3,4,5)
b=(2,4)
c=( $(sed 's/,/\n/g' <(printf "%s\n" "${a[@]}" "${b[@]}") | sort | uniq -u) )

В качестве альтернативы вы можете использовать вместо этого Perl:

#!/usr/bin/perl
my @A=(1,2,3,4,5);
my @B=(2,4);
my %k;
map{$k{$_}++} (@A,@B);
my @C=grep($k{$_}==1,keys(%k));
print "@C\n";

1Строго говоря, это массив с одним элементом, но по сути это то же самое, что и строка в отношении bash.

perl путь. Этот скрипт отображает все элементы в массиве a, которые также содержатся в массиве b,

#!/usr/bin/perl
my @a = (1,2,3,4,5);
my @b = (2,4,7,8,9,10);

# Create a hashmap with the entries in b as keys,
# but without values for the keys for a better lookup
# (exists ($hash{$element}))
my %hash;
@hash{@b}=();

foreach my $element (@a) {print "$element " unless exists($hash{$element})}
print "\n";

Выход:

1 3 5

Сложность задачи (O(N^2)) не может быть уменьшена; предполагая только то, что было дано явно (т.е. нет гипотезы для значений обоих массивов a а также b) код ниже просто проверит, присутствует ли каждое значение в a также присутствует в bи, если значение присутствует, оно сломает внутренний for цикл (единственная возможная оптимизация с данной гипотезой) и добавить значение к c; с большим количеством подсказок о содержимом массивов a а также b (т. е. если значения в каждом массиве могут быть повторены и если массивы отсортированы), может быть еще больше возможностей для улучшения:

#!/bin/bash

a=(1 2 3 4 5)
b=(2 4)
for i in ${a[@]}
do
match=0
    for j in ${b[@]}
    do
        if [ "${i}" == "${j}" ]
        then
            match=1
            break
        fi
    done
if [ "${match}" == 0 ]
then
    c+=($i)
fi
done
echo ${c[@]}

В python, записи, такие как:

a=(1,2,3,4,5)
b=(2,4)

являются повторяемыми и известны как tuples,

Ваша задача может быть легко выполнена в python:

#!/usr/bin/env python2
a = (1, 2, 3, 4, 5)
b = (2, 4)
c = tuple(i for i in a if i not in b)
print c

Выход:

(1, 3, 5)

Здесь мы нашли значения кортежа a, которые не существуют в кортеже b и положить их в другой кортеж c, Также обратите внимание, что эта операция будет быстрой и потребляющей память для больших наборов данных, так как мы использовали выражение генератора Python.

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

Вот чистое решение Bash для фактического удаления элементов, которые также находятся в (обратите внимание на дополнительный in):

      a=(1 2 3 4 5)
b=(2 4 6)
c=( $(printf "%s\n" "${a[@]}" "${b[@]}" "${b[@]}" | sort | uniq -u) )

будет состоять из 1 3 5и исключить неожиданное 6.

Обратите внимание: предполагается, что все значения уникальны. В противном случае они не будут отображаться в . Если содержит повторяющиеся значения, вы должны сначала удалить дубликаты (обратите внимание на повторяющиеся значения). 1в ):

      a=(1 1 2 3 4 5)
b=(2 4 6)
c=( $({ printf "%s\n" "${a[@]}" | sort -u; printf "%s\n" "${b[@]}" "${b[@]}"; } | sort | uniq -u) )

Если вы хотите реплицировать дубликаты в c, используйте ответ @kos. То же самое верно, если aа также bогромны: это очень неэффективное решение для многих элементов, даже если оно незначительно для нескольких элементов (<100). Если вам нужно обрабатывать огромные массивы, не используйте Bash.

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