¿Cómo se comparan dos matrices en bash para encontrar todos los valores que se cruzan?
Digamos:
array1 contiene los valores 1 y 2
array2 contiene los valores 2 y 3
Debería volver 2 como resultado.
Mi propia respuesta, que aún no puedo publicar debido a su pequeña reputación:
for item1 in $array1; do for item2 in $array2; do if [[ $item1 = $item2 ]]; then result=$result" "$item1 fi done done
Estoy buscando soluciones alternativas también.
Los elementos de la lista 1 se utilizan como expresión regular buscada en list2 (expresada como cadena: $ {list2 [*]}):
list1=( 1 2 3 4 6 7 8 9 10 11 12) list2=( 1 2 3 5 6 8 9 11 ) l2=" ${list2[*]} " # add framing blanks for item in ${list1[@]}; do if [[ $l2 =~ " $item " ]] ; then # use $item as regexp result+=($item) fi done echo ${result[@]}
El resultado es
1 2 3 6 8 9 11
Tomando la respuesta de @ Raihan y haciendo que funcione con archivos que no sean archivos (aunque se crean FD) Sé que es un poco engañoso, pero me pareció una buena alternativa
El efecto secundario es que la matriz de salida se clasificará lexicográficamente, espero que esté bien (tampoco sepa qué tipo de datos tiene, así que acabo de probar con números, puede haber trabajo adicional si necesita cadenas con caracteres especiales, etc.)
result=($(comm -12 <(for X in "${array1[@]}"; do echo "${X}"; done|sort) <(for X in "${array2[@]}"; do echo "${X}"; done|sort)))
Pruebas:
$ array1=(1 17 33 99 109) $ array2=(1 2 17 31 98 109) result=($(comm -12 <(for X in "${array1[@]}"; do echo "${X}"; done|sort) <(for X in "${array2[@]}"; do echo "${X}"; done|sort))) $ echo ${result[@]} 1 109 17
ps. Estoy seguro de que había una manera de sacar la matriz de un valor por línea sin el bucle for
, simplemente lo olvido (¿IFS?)
Si se tratara de dos archivos (en lugar de matrices) que buscaba líneas que se cruzan, podría usar el comando comm
.
$ comm -12 file1 file2
Su respuesta no funcionará, por dos razones:
$array1
simplemente se expande al primer elemento de array1
. (Al menos, en mi versión instalada de Bash es así como funciona. Eso no parece ser un comportamiento documentado, por lo que puede ser una peculiaridad dependiente de la versión). result
, el result
contendrá un espacio, por lo que la siguiente ejecución de result=$result" "$item1
se result=$result" "$item1
horrible. (En lugar de agregar al result
, ejecutará el comando que consiste en los dos primeros elementos, y el result
variable de entorno se establecerá en la cadena vacía.) Corrección: Resulta que estaba equivocado acerca de esto: la división de palabras no tener lugar dentro de las asignaciones. (Ver comentarios a continuación) Lo que quieres es esto:
result=() for item1 in "${array1[@]}"; do for item2 in "${array2[@]}"; do if [[ $item1 = $item2 ]]; then result+=("$item1") fi done done
Ahora que entiendo lo que quiere decir con “matriz”, creo, en primer lugar, que debe considerar el uso de arreglos Bash reales. Son mucho más flexibles, ya que (por ejemplo) los elementos del conjunto pueden contener espacios en blanco, y puede evitar el riesgo de que *
y ?
activará la expansión del nombre de archivo.
Pero si prefiere usar su enfoque existente de cadenas delimitadas por espacios en blanco, entonces estoy de acuerdo con la sugerencia de RHT de usar Perl:
result=$(perl -e 'my %array2 = map +($_ => 1), split /\s+/, $ARGV[1]; print join " ", grep $array2{$_}, split /\s+/, $ARGV[0] ' "$array1" "$array2")
(Los saltos de línea son solo para facilitar la lectura; puede deshacerse de ellos si lo desea).
En el comando Bash anterior, el progtwig Perl incorporado crea un hash llamado %array2
contiene los elementos de la segunda matriz, y luego imprime cualquier elemento de la primera matriz que existe en %array2
.
Esto se comportará de forma ligeramente diferente a su código en la forma en que maneja los valores duplicados en la segunda matriz; en su código, si array1
contiene x
dos veces y array2
contiene x
tres veces, el result
contendrá x
seis veces, mientras que en mi código, el result
contendrá x
solo dos veces. No sé si eso importa, ya que no conozco sus requisitos exactos.