Eu tenho duas matrizes como esta:
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)
As matrizes não são classificadas e podem até conter elementos duplicados.
Gostaria de fazer a interseção dessas duas matrizes e armazenar os elementos em outra matriz. Como eu faria isso?
Além disso, como obteria a lista de elementos que aparecem em B e não estão disponíveis em A?
foo
duas vezes), você precisa deles duplicados no resultado?Respostas:
comm(1)
é uma ferramenta que compara duas listas e pode fornecer a interseção ou diferença entre duas listas. As listas precisam ser classificadas, mas isso é fácil de alcançar.Para colocar suas matrizes em uma lista classificada adequada para
comm
:Isso transformará a matriz A em uma lista classificada. Faça o mesmo para B.
Para usar
comm
para retornar a interseção:-1 -2
diz para remover entradas exclusivas para o arquivo1 (A) e exclusivas para o arquivo2 (B) - a interseção dos dois.Para que ele retorne o que está no arquivo2 (B), mas não no arquivo1 (A):
-1 -3
diz para remover entradas exclusivas para arquivo1 e comuns para ambas - deixando apenas as únicas para arquivo2.Para alimentar dois pipelines
comm
, use o recurso "Substituição de Processo" debash
:Para capturar isso em uma matriz:
Juntando tudo:
fonte
\n
.\n
tente o seguinte: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
. Em vez disso, definaLC_COLLATE=C
o mesmo ganho de desempenho sem outros efeitos colaterais. Para obter resultados corretos, você também precisará definir o mesmo agrupamento para ocomm
qual foi usadosort
, por exemplo:unset LC_ALL; LC_COLLATE=C ; comm -12 <(printf '%s\n' "${A[@]}" | sort) <(printf '%s\n' "${B[@]}" | sort)
Você pode obter todos os elementos que estão em A e B percorrendo as duas matrizes e comparando:
Você pode obter todos os elementos em B, mas não em A, de maneira semelhante:
fonte
A
eB
,intersections
sempre será a mesma coisa até reordenar?Existe uma abordagem bastante elegante e eficiente para fazer isso, usando
uniq
- mas, precisaremos eliminar duplicatas de cada matriz, deixando apenas itens exclusivos. Se você deseja salvar duplicatas, existe apenas uma maneira "percorrendo as matrizes e comparando".Considere que temos duas matrizes:
Primeiro de tudo, vamos transformar essas matrizes em conjuntos. Vamos fazê-lo porque não há intersecção operação matemática que é conhecido como cruzamento de sets, e um conjunto é uma coleção de diferentes objetos, distintos ou únicos . Para ser sincero, não sei o que é "interseção" se falamos de listas ou sequências. Embora possamos escolher uma subsequência da sequência, mas esta operação (seleção) tem um significado ligeiramente diferente.
Então, vamos transformar!
Interseção:
Se você deseja armazenar os elementos em outra matriz:
uniq -d
significa mostrar apenas duplicatas (acho queuniq
é bastante rápido por causa de sua realização: acho que é feito comXOR
operação).Obtenha a lista de elementos que aparecem
B
e não estão disponíveisA
, por exemploB\A
Ou, ao salvar em uma variável:
Assim, primeiro obtemos a interseção de
A
eB
(que é simplesmente o conjunto de duplicatas entre eles), digamos que éA/\B
, e depois usamos a operação de inversão de interseção deB
eA/\B
(que são apenas elementos únicos), então obtemosB\A = ! (B /\ (A/\B))
.PS
uniq
foi escrito por Richard M. Stallman e David MacKenzie.fonte
Ignorando a eficiência, aqui está uma abordagem:
fonte
Meu caminho puro bash
Como essas variáveis contêm apenas
vol-XXX
ondeXXX
existe um número hexadecimal, existe uma maneira rápida de usar matrizes bashIsso deve gerar:
Nesse estado, o ambiente do bash contém:
Então você poderia:
Isso renderizará:
Mas isso é ordenado numericamente! Se você quiser um pedido original, poderá:
Então, você exibe vols na mesma ordem que os enviados:
ou
por mostrar apenas em A :
ou até:
vai voltar a imprimir :
fonte
Duplicate
linhas são inúteis, elas podem simplesmente ser descartadas.