使用AWK对关联数组进行排序

时间:2011-03-17 17:25:05

标签: awk gawk asort

这是我的数组(gawk脚本):

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

排序后,我需要以下结果:

bob    5
jack   11
peter  32
john   463

当我使用“asort”时,索引会丢失。如何按数组值排序而不丢失索引? (我需要根据他们的价值订购指数)

(我需要仅使用awk / gawk获取此结果,而不是shell脚本,perl等)

如果我的帖子不够清楚,这里有另一篇文章解释同一问题:http://www.experts-exchange.com/Programming/Languages/Scripting/Shell/Q_26626841.html

提前致谢

更新:

多谢你们两个,但我需要按值排序,而不是索引(我希望根据值来排序索引)。

换句话说,我需要这个结果:

bob    5
jack   11
peter  32
john   463

不是:

bob 5
jack 11
john 463
peter 32

(我同意,我的例子令人困惑,选择的值非常糟糕)

从Catcall的代码中,我编写了一个可行的快速实现,但它相当丑陋(我在排序和分割之前将键和值组合在一起)。这是它的样子:

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

当然,如果你有更干净的东西,我很感兴趣...

感谢您的时间

6 个答案:

答案 0 :(得分:22)

修改

按值排序

哦!要对进行排序,它有点像kludge,但您可以使用值和原始数组的索引的串联作为新数组中的索引来创建临时数组。然后你可以asorti()临时数组并将连接的值拆分回索引和值。如果您无法遵循那种错综复杂的描述,则代码更容易理解。它也很短。

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

编辑2:

如果您有GAWK 4,则可以按值的顺序遍历数组而不执行显式排序:

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

 }

有按索引或值,升序或降序以及其他选项遍历的设置。您还可以指定自定义功能。

上一个回答:

按索引排序

如果您有支持gawk的{​​{1}} 3.1.2或更高版本的AWK:

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

asorti()

答案 1 :(得分:5)

将Unix排序命令与管道一起使用,保持Awk代码简单并遵循Unix哲学 创建一个输入文件,其值由逗号分隔 彼得,32
千斤顶,11
约翰,463
鲍勃,5

使用代码

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

运行程序,应该给你输出
$ awk -f sort.awk数据
鲍勃,5
千斤顶,11
彼得,32
约翰,463

答案 2 :(得分:3)

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

在迭代数组之前,请使用上面的语句。但是,它适用于awk 4.0.1版。它在awk 3.1.7版本中不起作用。

我不确定它是在哪个中间版本中引入的。

答案 3 :(得分:1)

简单的答案......

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

答案 4 :(得分:0)

The Awk Programming Language 的作者提供quicksort function,可在线获取。

我认为你会做这样的事情。

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]];
  }
}

答案 5 :(得分:0)

使用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]
    }
}