Tengo un archivo de pestañas con dos columnas como esa

5 6 14 22 23 25 27 84 85 88 89 94 95 98 100             6 94
6 8 17 20 193 205 209 284 294 295 299 304 305 307 406   205 284 307 406
2 10 13 40 47 58                                        2 13 40 87

Y la salida deseada debe ser

5 6 14 22 23 25 27 84 85 88 89 94 95 98 100             14 27
6 8 17 20 193 205 209 284 294 295 299 304 305 307 406   6 209 299 305
2 10 13 23 40 47 58 87                                  10 23 40 58

Me gustaría cambiar los números en la segunda columna por números aleatorios en la primera columna, lo que da como resultado una salida en la segunda columna con el mismo número de números. Me refiero a p. si hay cuatro números en la segunda columna para la fila x, la salida debe tener cuatro números aleatorios de la primera columna para esta fila, y así sucesivamente ...

Estoy tratando de crear dos matrices por AWK y dividir y reemplazar cada número en la segunda columna por números en la primera columna, pero no de manera aleatoria. He visto la función rand () pero no sé exactamente cómo se unen estas dos cosas en un script. ¿Es posible hacerlo en un entorno BASH o hay otras formas mejores de hacerlo en un entorno BASH? Gracias por adelantado

1
Perceval Vellosillo Gonzalez 10 may. 2019 a las 13:58

3 respuestas

La mejor respuesta

¡awk al rescate!

$ awk -F'\t' 'function shuf(a,n)
                 {for(i=1;i<n;i++)
                    {j=i+int(rand()*(n+1-i));
                     t=a[i]; a[i]=a[j]; a[j]=t}}
             function join(a,n,x,s)
                  {for(i=1;i<=n;i++) {x=x s a[i]; s=" "}
                   return x}
             BEGIN{srand()}
                  {an=split($1,a," ");
                   shuf(a,an);
                   bn=split($2,b," ");
                   delete m; delete c; j=0;
                   for(i=1;i<=bn;i++) m[b[i]];
                   # pull elements from a upto required sample size, 
                   # not intersecting with the previous sample set
                   for(i=1;i<=an && j<bn;i++) if(!(a[i] in m)) c[++j]=a[i];
                   cn=asort(c);
                   print $1 FS join(c,cn)}' file


5 6 14 22 23 25 27 84 85 88 89 94 95 98 100     85 94
6 8 17 20 193 205 209 284 294 295 299 304 305 307 406   20 205 294 295
2 10 13 23 40 47 58 87  10 13 47 87

Baraja (algoritmo estándar) la matriz de entrada, muestra el número requerido de elementos, el requisito adicional no es una intersección con el conjunto de muestras existente. Mapa de estructura auxiliar para mantener el conjunto de muestras existente y utilizado para pruebas en . El resto debería ser fácil de leer.

1
karakfa 13 may. 2019 a las 16:03

Prueba esto:

# This can be an external file of course
# Note COL1 and COL2 seprated by hard TAB

cat <<EOF > d1.txt
5 6 14 22 23 25 27 84 85 88 89 94 95 98 100     6 94
6 8 17 20 193 205 209 284 294 295 299 304 305 307 406   205 284 307 406
2 10 13 40 47 58        2 13 40 87
EOF

# Loop to read each line, not econvert TAB to:, though could have used IFS

cat d1.txt | sed 's/    /:/' | while read LINE
do
   # Get the 1st column data

   COL1=$( echo ${LINE} | cut -d':' -f1 )

   # Get col1 number of items

   NUM_COL1=$( echo ${COL1} | wc -w )

   # Get col2 number of items

   NUM_COL2=$( echo ${LINE} | cut -d':' -f2 | wc -w )

   # Now split col1 items into an array

   read -r -a COL1_NUMS <<< "${COL1}"


   COL2=" "

   # THis loop runs once for each COL2 item

   COUNT=0
   while [ ${COUNT} -lt ${NUM_COL2} ]
   do

      # Generate a random number to use as teh random index for COL1

      COL1_IDX=${RANDOM}
      let "COL1_IDX %= ${NUM_COL1}"

      NEW_NUM=${COL1_NUMS[${COL1_IDX}]}

      # Check for duplicate

      DUP_FOUND=$( echo "${COL2}" | grep ${NEW_NUM} )

      if [ -z "${DUP_FOUND}" ]
      then
         # Not a duplicate, increment loop conter and do next one

         let "COUNT = COUNT + 1 "

         # Add the random COL1 item to COL2

         COL2="${COL2} ${COL1_NUMS[${COL1_IDX}]}"
      fi
   done

   # Sort COL2

   COL2=$( echo ${COL2} | tr ' ' '\012' | sort -n | tr '\012' ' ' )

   # Print

   echo ${COL1} :: ${COL2}
done

Salida:

5 6 14 22 23 25 27 84 85 88 89 94 95 98 100 :: 88 95
6 8 17 20 193 205 209 284 294 295 299 304 305 307 406 :: 20 299 304 305
2 10 13 40 47 58 :: 2 10 40 58
0
TenG 10 may. 2019 a las 11:53

Suponiendo que hay una pestaña que delimita las dos columnas, y cada columna es una lista delimitada por espacios:

awk 'BEGIN{srand()} 
    {n=split($1,a," "); 
    m=split($2,b," "); 
    printf "%s\t",$1; 
    for (i=1;i<=m;i++) 
        printf "%d%c", a[int(rand() * n) +1], (i == m) ? "\n" : " "
    }' FS=\\t input
1
William Pursell 10 may. 2019 a las 12:24