Mam dwie takie tablice:
A=(vol-175a3b54 vol-382c477b vol-8c027acf vol-93d6fed0 vol-71600106 vol-79f7970e vol-e3d6a894 vol-d9d6a8ae vol-8dbbc2fa vol-98c2bbef vol-ae7ed9e3 vol-5540e618 vol-9e3bbed3 vol-993bbed4 vol-a83bbee5 vol-ff52deb2)
B=(vol-175a3b54 vol-e38d0c94 vol-2a19386a vol-b846c5cf vol-98c2bbef vol-7320102b vol-8f6226cc vol-27991850 vol-71600106 vol-615e1222)
Tablice nie są sortowane i mogą nawet zawierać zduplikowane elementy.
Chciałbym zrobić przecięcie tych dwóch tablic i przechowywać elementy w innej tablicy. Jak mam to zrobić?
Ponadto, jak mogę uzyskać listę elementów, które pojawiają się w B i nie są dostępne w A?
foo
dwa razy), czy potrzebujesz ich w wyniku?Odpowiedzi:
comm(1)
to narzędzie, które porównuje dwie listy i może dać ci przecięcie lub różnicę między dwiema listami. Listy należy posortować, ale łatwo to osiągnąć.Aby uzyskać tablice na posortowaną listę odpowiednią dla
comm
:To zmieni tablicę A w posortowaną listę. Zrób to samo dla B.
Aby użyć,
comm
aby zwrócić skrzyżowanie:-1 -2
mówi, aby usunąć wpisy unikalne dla file1 (A) i unikalne dla file2 (B) - przecięcie tych dwóch.Aby to zwróciło to, co jest w pliku 2 (B), ale nie w pliku 1 (A):
-1 -3
mówi, aby usunąć wpisy unikalne dla pliku 1 i wspólne dla obu - pozostawiając tylko te unikalne dla pliku 2.Aby zasilić dwa rurociągi
comm
, użyj funkcji „Process Substitution” wbash
:Aby przechwycić to w tablicy:
Kładąc wszystko razem:
źródło
\n
.\n
spróbuj tego:arr1=( one two three "four five\nsix\nseven" ); arr2=( ${arr1[@]:1} "four five\\nsix" ); n1=${#arr1[@]}; n2=${#arr2[@]}; arr=( ${arr1[@]/ /'-_-'} ${arr2[@]/ /'-_-'} ); arr=( $( echo "${arr[@]}"|tr '\t' '-t-'|tr '\n' '-n-'|tr '\r' '-r-' ) ); arr1=( ${arr[@]:0:${n1}} ); arr2=( ${arr[@]:${n1}:${n2}} ); unset arr; printf "%0.s-" {1..10}; printf '\n'; printf '{'; printf " \"%s\" " "${arr1[@]}"; printf '}\n'; printf "%0.s-" {1..10}; printf '\n'; printf '{'; printf " \"%s\" " "${arr2[@]}"; printf '}\n'; printf "%0.s-" {1..10}; printf '\n\n'; unset arr1; unset arr2
LC_ALL=C
. Zamiast tego ustawLC_COLLATE=C
ten sam przyrost wydajności bez innych efektów ubocznych. W celu uzyskania poprawnych wyników należy również ustawić takie samo zestawienie,comm
jakie zastosowanosort
, np .:unset LC_ALL; LC_COLLATE=C ; comm -12 <(printf '%s\n' "${A[@]}" | sort) <(printf '%s\n' "${B[@]}" | sort)
Możesz uzyskać wszystkie elementy, które są zarówno w A, jak i B, zapętlając obie tablice i porównując:
Możesz uzyskać wszystkie elementy w B, ale nie w A w podobny sposób:
źródło
A
iB
czyintersections
zawsze to samo dotyczy zmiany kolejności?Jest to dość eleganckie i wydajne podejście do tego, używając
uniq
- ale będziemy musieli wyeliminować duplikaty z każdej tablicy, pozostawiając tylko unikalne przedmioty. Jeśli chcesz zapisać duplikaty, istnieje tylko jeden sposób: „zapętlając obie tablice i porównując”.Rozważmy, że mamy dwie tablice:
Po pierwsze, pozwólmy przekształcić te tablice w zestawy. Zrobimy to, ponieważ istnieje przecięcie operacji matematycznych, które jest znane jako przecięcie zbiorów, a zbiór jest zbiorem różnych obiektów, wyraźnych lub niepowtarzalnych . Szczerze mówiąc, nie wiem, co to jest „skrzyżowanie”, jeśli mówimy o listach lub sekwencjach. Chociaż możemy wybrać podsekwencję z sekwencji, ale ta operacja (wybór) ma nieco inne znaczenie.
Przekształćmy się!
Skrzyżowanie:
Jeśli chcesz przechowywać elementy w innej tablicy:
uniq -d
oznacza pokaż tylko duplikaty (myślę, żeuniq
jest dość szybki ze względu na jego realizację: Myślę, że jest to zrobione zXOR
operacją).Uzyskaj listę elementów, które pojawiają się
B
i nie są dostępne wA
, tjB\A
Lub z zapisaniem w zmiennej:
Tak więc, na początku mamy przecięcie
A
iB
(który jest po prostu zbiorem duplikatów między nimi), powiedzmy, że takA/\B
, a następnie zastosowaliśmy operację odwracania przecięciaB
iA/\B
(co jest po prostu tylko unikatowymi elementami), więc otrzymujemyB\A = ! (B /\ (A/\B))
.PS
uniq
napisali Richard M. Stallman i David MacKenzie.źródło
Ignorując wydajność, oto podejście:
źródło
Mój czysty bash sposób
Ponieważ zmienne te zawierają tylko
vol-XXX
tam, gdzieXXX
jest liczba szesnastkowa, istnieje szybki sposób na użycie tablic bashTo musi generować:
W tym stanie środowisko bash zawiera:
Więc możesz:
To spowoduje:
Ale to jest posortowane numerycznie! Jeśli chcesz oryginalne zamówienie, możesz:
Więc wyświetlasz vols w tej samej kolejności, w jakiej zostały przesłane:
lub
za pokazywanie tylko w A :
lub nawet:
będzie ponownie wydrukować :
źródło
Duplicate
linie są bezużyteczne, można je po prostu upuścić.