Pregunta

Aquí está mi matriz (script gawk):

myArray["peter"] = 32
myArray["bob"] = 5
myArray["john"] = 463
myArray["jack"] = 11

Después de ordenar, necesito el siguiente resultado:

bob    5
jack   11
peter  32
john   463

Cuando uso "asort", los índices se pierden.¿Cómo ordenar por valor de matriz sin perder índices?(Necesito índices ordenados según sus valores)

(Necesito obtener este resultado solo con awk/gawk, no con shell script, perl, etc.)

Si mi publicación no es lo suficientemente clara, aquí hay otra publicación que explica el mismo problema: http://www.experts-exchange.com/Programming/Languages/Scripting/Shell/Q_26626841.html )

gracias de antemano

Actualizar :

Gracias a ambos, pero necesito ordenar por valores, no por índices (quiero índices ordenados según sus valores).

En otros términos, necesito este resultado:

bob    5
jack   11
peter  32
john   463

no :

bob 5
jack 11
john 463
peter 32

(Estoy de acuerdo, mi ejemplo es confuso, los valores elegidos son bastante malos)

A partir del código de Catcall, escribí una implementación rápida que funciona, pero es bastante fea (concateno claves y valores antes de ordenar y dividir durante la comparación).Así es como se ve:

function qsort(A, left, right,   i, last) {
  if (left >= right)
    return
  swap(A, left, left+int((right-left+1)*rand()))
  last = left
  for (i = left+1; i <= right; i++)
    if (getPart(A[i], "value") < getPart(A[left], "value"))
      swap(A, ++last, i)
  swap(A, left, last)
  qsort(A, left, last-1)
  qsort(A, last+1, right)
}

function swap(A, i, j,   t) {
  t = A[i]; A[i] = A[j]; A[j] = t
}

function getPart(str, part) {
  if (part == "key")
    return substr(str, 1, index(str, "#")-1)
  if (part == "value")
    return substr(str, index(str, "#")+1, length(str))+0
  return
}

BEGIN {  }
      {  }
END {

  myArray["peter"] = 32
  myArray["bob"] = 5
  myArray["john"] = 463
  myArray["jack"] = 11

  for (key in myArray)
    sortvalues[j++] = key "#" myArray[key]

  qsort(sortvalues, 0, length(myArray));

  for (i = 1; i <= length(myArray); i++)
    print getPart(sortvalues[i], "key"), getPart(sortvalues[i], "value")
}

Por supuesto que me interesa si tienes algo más limpio...

Gracias por tu tiempo

¿Fue útil?

Solución

Editar:

Ordenar por valores

¡Vaya! Para ordenar el valores, es un poco un kludge, pero puede crear una matriz temporal utilizando una concatenación de los valores y los índices de la matriz original como índices en la nueva matriz. Entonces tú puedes asorti() La matriz temporal y dividen los valores concatenados nuevamente en índices y valores. Si no puede seguir esa descripción enrevesada, el código es mucho más fácil de entender. También es muy corto.

# right justify the integers into space-padded strings and cat the index
# to create the new index
for (i in myArray) tmpidx[sprintf("%12s", myArray[i]),i] = i
num = asorti(tmpidx)
j = 0
for (i=1; i<=num; i++) {
    split(tmpidx[i], tmp, SUBSEP)
    indices[++j] = tmp[2]  # tmp[2] is the name
}
for (i=1; i<=num; i++) print indices[i], myArray[indices[i]]

Editar 2:

Si tiene BAWK 4, puede atravesar la matriz por orden de valores sin realizar un tipo explícito:

#!/usr/bin/awk -f
BEGIN {
    myArray["peter"] = 32
    myArray["bob"] = 5
    myArray["john"] = 463
    myArray["jack"] = 11

    PROCINFO["sorted_in"] = "@val_num_asc"

    for (i in myArray) {
        {print i, myArray[i]}}
    }

 }

Hay configuraciones para atravesar el índice o el valor, ascender o descender y otras opciones. También puede especificar una función personalizada.

Respuesta anterior:

Ordenar por índices

Si tienes un AWK, como gawk 3.1.2 o mayor, que admite asorti():

#!/usr/bin/awk -f
BEGIN {
    myArray["peter"] = 32
    myArray["bob"] = 5
    myArray["john"] = 463
    myArray["jack"] = 11

    num = asorti(myArray, indices)
    for (i=1; i<=num; i++) print indices[i], myArray[indices[i]]
}

Si no tienes asorti():

#!/usr/bin/awk -f
BEGIN {
    myArray["peter"] = 32
    myArray["bob"] = 5
    myArray["john"] = 463
    myArray["jack"] = 11

    for (i in myArray) indices[++j] = i
    num = asort(indices)
    for (i=1; i<=num; i++) print i, indices[i], myArray[indices[i]]
}

Otros consejos

Use el comando de clasificación Unix con la tubería, mantiene el código AWK simple y sigue la filosofía de Unix
Crear un archivo de entrada con valores separados por coma
Peter, 32
Jack, 11
John, 463
Bob, 5

Crear un archivo sort.awk con el código

BEGIN { FS=","; }
{
    myArray[$1]=$2;
}
END {
    for (name in myArray)
        printf ("%s,%d\n", name, myArray[name]) | "sort -t, -k2 -n"
}

Ejecutar el programa, debería darle la salida
$ awk -f sort.awk datos
Bob, 5
Jack, 11
Peter, 32
John, 463

PROCINFO["sorted_in"] = "@val_num_desc";

Antes de iterar una matriz, use la declaración anterior. Pero funciona en AWK versión 4.0.1. No funciona en AWK Versión 3.1.7.

No estoy seguro de qué versión intermedia, se introdujo.

Y la respuesta simple ...

function sort_by_myArray(i1, v1, i2, v2) {
    return myArray[i2] < myArray[i1];
}

BEGIN {
    myArray["peter"] = 32;
    myArray["bob"] = 5;
    myArray["john"] = 463;
    myArray["jack"] = 11;
    len = length(myArray);

    asorti(myArray, k, "sort_by_myArray");

    # Print result.
    for(n = 1; n <= len; ++n) {
            print k[n], myArray[k[n]]
    }
}

Los autores de El lenguaje de programación AWK proporcionar una función rápida, que está disponible en línea.

Creo que harías algo como esto.

END {
  for (key in myArray) {
    sortkeys[j++] = key;
  }
  qsort(sortkeys, 0, length(myArray));      # Not sure I got the args right.
  for (i = 1; i <= length(myArray); i++) {
    print sortkeys[i], myArray[sortkeys[i]];
  }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top