2012-05-25 14 views
15

que darse cuenta de que awk tiene matrices asociativas, pero me pregunto si hay una awk equivalente a esto:¿Es posible agregar un elemento a una matriz en awk sin especificar un índice?

http://php.net/manual/en/function.array-push.php

La solución obvia es simplemente decir:

array[$new_element] = $new_element 

Sin embargo, esto parece menos legible y más hackish de lo que necesita ser.

+2

¡Llamaría así de elegante y minimalista, no de hackish! ;-). Siempre puede escribir sus propias funciones para administrar matrices, pero no hay nada integrado en el lenguaje para eso. Buena suerte. – shellter

Respuesta

8

No creo que la longitud de una matriz esté inmediatamente disponible en awk (al menos no en las versiones con las que jugueteo). Sin embargo, usted podría simplemente mantener la longitud y luego hacer algo como esto:

array[arraylen++] = $0; 

y luego acceder a los elementos que a través de los mismos valores enteros:

for (i = 0; i < arraylen; i++) 
    print array[i]; 
+0

+1 - La función 'length()' en GAWK devolverá el número de elementos en una matriz, pero como las matrices son dispersas, la longitud no es necesariamente el último elemento. –

+1

Solo para referencia histórica, la notación 'length (arrayname)' no es exclusiva de GAWK. Fue [agregado] (https://github.com/onetrueawk/awk/blob/master/FIXES#L322) al One True Awk en 2002. Puede ser que esta funcionalidad haya tocado a gawk [tres años después] (http: //code.metager.de/source/xref/gnu/gawk/ChangeLog.0#3453). – ghoti

6

En gawk se puede encontrar la longitud de una matriz con length(var) por lo que no es muy difícil cocinar su propia función.

function push(A,B) { A[length(A)+1] = B } 

Aviso esta discusión, sin embargo: http://objectmix.com/awk/361598-gawk-length-array-question.html - todos los lugares a los que puede tener acceso en este momento tiene gawk 3.1.5 así que no puedo probar correctamente mi función, duh. Pero aquí hay una aproximación.

vnix$ gawk '# BEGIN: make sure arr is an array 
> BEGIN { delete arr[0] } 
> { print "=" length(arr); arr[length(arr)+1] = $1; 
>  print length(arr), arr[length(arr)] } 
> END { print "---"; 
>  for (i=1; i<=length(arr); ++i) print i, arr[i] }' <<HERE 
> fnord foo 
> ick bar 
> baz quux 
> HERE 
=0 
1 fnord 
=1 
2 ick 
=2 
3 baz 
--- 
1 fnord 
2 ick 
3 baz 
+1

El fragmento 'A [longitud (A) +1]' no está garantizado para evitar colisiones. Funciona en casos, como su ejemplo, donde solo agrega cosas a la matriz en un orden predecible. Sin embargo, si eliminara elementos de la matriz, crearía lagunas que reducirían 'length()' mientras dejaba el número más alto en su lugar. – ghoti

1

Como han dicho otros, awk no ofrece una funcionalidad como esta de fábrica. Su solución "hackish" puede funcionar para algunos conjuntos de datos, pero no para otros. Considere que puede agregar el mismo valor de matriz dos veces, y quiere que se represente dos veces dentro de la matriz.

$ echo 3 | awk 'BEGIN{ a[1]=5; a[2]=12; a[3]=2 } 
> { a[$1] = $1 } 
> END {print length(a) " - " a[3]}' 
3 - 3 

La mejor solución puede ser informada por los datos que están en la matriz, pero he aquí algunas ideas.

En primer lugar, si está seguro de que su índice siempre será numérico, siempre comenzará en 1 y nunca eliminará los elementos de la matriz, entonces la sugerencia de triplee de A[length(A)+1]="value" puede funcionar para usted. Pero si elimina un elemento, su próxima escritura puede sobrescribir su último elemento.

Si su índice no importa, y no le preocupa desperdiciar espacio con las teclas largas, podría utilizar un número aleatorio que sea lo suficientemente largo como para reducir la probabilidad de colisiones. Una opción & sucia rápida podría ser:

srand() 
a[rand() rand() rand()]="value" 

recuerde utilizar srand() para una mejor asignación al azar, y no confiar en rand() para producir números aleatorios reales. Esta es una solución menos que perfecta en varias formas, pero tiene la ventaja de ser una sola línea de código.

Si sus teclas son numéricos, pero posiblemente escasa, como en el ejemplo que rompería la solución de tripleee, se puede añadir una pequeña búsqueda a su función de empuje:

function push (a, v,  n) { 
    n=length(a)+1 
    while (n in a) n++ 
    a[n]=v 
} 

El bucle while asegura que' Asignaremos un índice no utilizado.Esta función también es compatible con matrices que usan índices no numéricos: asigna claves que son numéricas, pero no importa lo que ya está allí.

Tenga en cuenta que awk no garantiza el orden de los elementos dentro de una matriz, por lo que la idea de que "empujará un elemento al final de la matriz" es incorrecta. Agregará este elemento a la matriz, pero no hay garantía de que aparezca como el último cuando ingrese al lazo for.

$ cat a 
#!/usr/bin/awk -f 

function push (a, v,  n) { 
    n=length(a)+1 
    while (n in a) n++ 
    a[n]=v 
} 

{ 
    push(a, $0) 
} 

END { 
    print "length=" length(a) 
    for(i in a) print i " - " a[i] 
} 

$ printf '3\nfour\ncinq\n' | ./a 
length=3 
2 - four 
3 - cinq 
1 - 3 
Cuestiones relacionadas