17 votes

Trier un tableau associatif avec AWK

Voici mon tableau (gawk script) :

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

Après le tri, j'ai besoin du résultat suivant :

bob    5
jack   11
peter  32
john   463

Lorsque j'utilise "asort", les indices sont perdus. Comment trier par valeur de tableau sans perdre les indices ? (J'ai besoin d'indices ordonnés en fonction de leurs valeurs).

(J'ai besoin d'obtenir ce résultat avec awk/gawk seulement, pas avec le shell script, perl, etc)

Si mon message n'est pas assez clair, voici un autre message expliquant le même problème : http://www.experts-exchange.com/Programming/Languages/Scripting/Shell/Q_26626841.html )

Merci d'avance

Mise à jour :

Merci à vous deux, mais j'ai besoin de trier par valeurs, pas par indices (je veux des indices ordonnés selon leurs valeurs).

En d'autres termes, j'ai besoin de ce résultat :

bob    5
jack   11
peter  32
john   463

pas :

bob 5
jack 11
john 463
peter 32

(je suis d'accord, mon exemple est confus, les valeurs choisies sont plutôt mauvaises)

A partir du code de Catcall, j'ai écrit une implémentation rapide qui fonctionne, mais qui est plutôt moche (je concatène les clés et les valeurs avant le tri et je les sépare pendant la comparaison). Voici à quoi ça ressemble :

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")
}

Bien sûr, je suis intéressé si vous avez quelque chose de plus propre...

Merci pour votre temps

29voto

Dennis Williamson Points 105818

Edit :

Trier par valeurs

Oh ! Pour trier le valeurs Si vous voulez créer un tableau temporaire, c'est un peu compliqué, mais vous pouvez créer un tableau temporaire en utilisant une concaténation des valeurs et des indices du tableau original comme indices dans le nouveau tableau. Ensuite, vous pouvez asorti() le tableau temporaire et divise les valeurs concaténées en indices et valeurs. Si vous ne pouvez pas suivre cette description alambiquée, le code est beaucoup plus facile à comprendre. Il est également très court.

# 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]]

Edit 2 :

Si vous disposez de GAWK 4, vous pouvez parcourir le tableau par ordre de valeurs sans effectuer de tri explicite :

#!/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]}}
    }

 }

Il existe des paramètres pour le parcours par index ou par valeur, par ordre croissant ou décroissant et d'autres options. Vous pouvez également spécifier une fonction personnalisée.

Réponse précédente :

Trier par indices

Si vous disposez d'un AWK, tel que gawk 3.1.2 ou supérieur, qui prend en charge 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 vous n'avez pas 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]]
}

5voto

Sal Kadam Points 67

Utilisez la commande de tri Unix avec le pipe, pour garder le code Awk simple et suivre la philosophie Unix.
Créez un fichier d'entrée avec des valeurs séparées par des virgules.
peter,32
jack,11
john,463
bob,5

Créez un fichier sort.awk avec le code suivant

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

Exécutez le programme, vous devriez obtenir le résultat suivant
$ awk -f sort.awk data
bob,5
jack,11
peter,32
john,463

4voto

K Adithyan Points 376
PROCINFO["sorted_in"] = "@val_num_desc";

Avant d'itérer un tableau, utilisez l'instruction ci-dessus. Mais, elle fonctionne dans la version 4.0.1 de l'awk. Elle ne fonctionne pas dans la version 3.1.7 de l'awk.

Je ne suis pas sûr dans quelle version intermédiaire, il a été introduit.

1voto

Carlo Wood Points 1275

Et la réponse 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]]
    }
}

0voto

Edward Points 323

Utilisez asorti :

#!/usr/bin/env -S gawk -f
{
    score[$1] = $0;
    array[sprintf("%3s",$2) $1] = $1;
}

END {
    asorti(array, b)
    for(i in b)
    {
        name = array[b[i]]
        print score[name]
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X