如何在awk中初始化数组数组?

Bea*_*ode 25 arrays awk initialization

是否可以在AWK中初始化这样的数组?

Colors[1] = ("Red", "Green", "Blue")
Colors[2] = ("Yellow", "Cyan", "Purple")
Run Code Online (Sandbox Code Playgroud)

然后有一个二维数组,其中Colors [2,3] ="Purple".


另一个线程我明白这是不可能的("遗憾的是,没有办法在不滥用split()的情况下一次设置一个数组").无论如何,我想100%肯定,我确信还有其他人有同样的问题.

我正在寻找最简单的方法来初始化像上面那样的数组,将它编写得很好.

Jon*_*ler 13

您可以轻松地创建二维数组.你不能做的,AFAIK,是在一次操作中初始化它.正如dmckee在注释中暗示的那样,无法初始化数组的原因之一是对下标的类型没有限制,因此不要求它们是纯数字.您可以在下面的脚本中执行多项任务.下标由变量SUBSEP指定的模糊字符正式分隔,默认值为034(U + 001C,FILE SEPARATOR).显然,如果其中一个索引包含此字符,则会出现混淆(但是最后一次在字符串中使用该字符是什么时候?).

BEGIN {
    Colours[1,1] = "Red"
    Colours[1,2] = "Green"
    Colours[1,3] = "Blue"
    Colours[2,1] = "Yellow"
    Colours[2,2] = "Cyan"
    Colours[2,3] = "Purple"
}
END {
    for (i = 1; i <= 2; i++)
        for (j = 1; j <= 3; j++)
            printf "Colours[%d,%d] = %s\n", i, j, Colours[i,j];
}
Run Code Online (Sandbox Code Playgroud)

示例运行:

$ awk -f so14063783.awk /dev/null
Colours[1,1] = Red
Colours[1,2] = Green
Colours[1,3] = Blue
Colours[2,1] = Yellow
Colours[2,2] = Cyan
Colours[2,3] = Purple
$
Run Code Online (Sandbox Code Playgroud)


Bea*_*ode 12

谢谢你的回答.无论如何,对于那些想要初始化一维数组的人来说,这是一个例子:

SColors = "Red_Green_Blue"
split(SColors, Colors, "_")
print Colors[1] " - " Colors[2] " - " Colors[3]
Run Code Online (Sandbox Code Playgroud)

  • 你问了一个关于初始化多维数组的问题,对你的问题得到了很好的答案,但是你把自己的答案发布到了另一个问题并接受了.其他人看到了什么问题?无论如何,正确的答案是[@ Steve's](http://stackoverflow.com/a/14064658/1745001). (11认同)

Ste*_*eve 10

如果有GNU awk,则可以使用真正的多维数组.虽然这个答案使用了这个split()功能,但它肯定不会滥用它.运行如下:

awk -f script.awk
Run Code Online (Sandbox Code Playgroud)

内容script.awk:

BEGIN {

    x=SUBSEP

    a="Red" x "Green" x "Blue"
    b="Yellow" x "Cyan" x "Purple"

    Colors[1][0] = ""
    Colors[2][0] = ""

    split(a, Colors[1], x)
    split(b, Colors[2], x)

    print Colors[2][3]
}
Run Code Online (Sandbox Code Playgroud)

结果:

Purple
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 8

现有的答案很有帮助,并且涵盖了所有方面,但我想我应该给出更有针对性的总结。

这个问题混淆了两个方面:

  • 一般在 Awk 中初始化数组
  • 这样做是为了特别填充二维数组

数组初始化:

Awk 没有数组文字(初始化程序)语法。

最简单的解决方法是:

  • 将数组元素表示为单个字符串,并且
  • 使用该split()函数将该字符串拆分为数组的元素。
$ awk 'BEGIN { n=split("Red Green Blue", arr); for (i=1;i<=n;++i) print arr[i] }'
Red
Green
Blue
Run Code Online (Sandbox Code Playgroud)

这就是OP在他们自己的有用答案中所做的。

如果元素本身包含空格,请使用不属于数据的自定义分隔符,|在此示例中:

$ awk 'BEGIN { n=split("Red (1)|Green (2)", arr, "|"); for (i=1;i<=n;++i) print arr[i] }'
Red (1)
Green (2)
Run Code Online (Sandbox Code Playgroud)

二维数组的初始化:

  • 根据 POSIX,Awk没有真正的多维数组,只是使用一维数组对其进行模拟,该数组的索引与内置变量的值隐式连接SUBSEP以形成单个键(索引;请注意,所有Awk 数组都是联想)。

    • arr[1, 2]实际上与 相同arr[1 SUBSEP 2],其中1 SUBSEP 2是构建键值的字符串连接。
    • 因为不存在真正的多个维度 - 只有复合键的平面数组 - 您无法使用 单独枚举(伪)维度for (i in ...),例如仅获取主(伪)维度的所有子索引1
    • 默认值为“INFORMATION SEPARATOR ONE”字符SUBSEP,这是一个很少使用的控制字符,不太可能出现在日期中;在 ASCII 和 UTF-8 中,它表示为单字节;如果需要,您可以更改该值。0x1f
  • 相比之下,GNU Awk作为一个非标准扩展,确实支持真正的多维数组

    • 重要提示:您必须始终单独指定索引;例如,arr[1,2]您必须使用arr[1][2].

POSIX 兼容示例(类似于TrueY 的有用答案):

awk 'BEGIN {
  n=split("Red Green Blue", arrAux); for (i in arrAux) Colors[1,i] = arrAux[i]
  n=split("Yellow Cyan Purple", arrAux); for (i in arrAux) Colors[2,i] = arrAux[i]
  print Colors[1,2]
  print "---"
  # Enumerate all [2,*] values - see comments below.
  for (i in Colors) { if (index(i, 2 SUBSEP)==1) print Colors[i] }
}'
Green
---
Yellow
Cyan
Purple
Run Code Online (Sandbox Code Playgroud)

请注意,使用复合键用一维数组模拟多维数组具有以下不方便的含义

  • auxArr需要辅助数组,因为您无法直接填充数组的给定(伪)维度。

  • 您不能使用 枚举仅一个(伪)维度for (i in ...),只能枚举跨(伪)维度的所有索引。

    • for (i in Colors) { if (index(i, 2 SUBSEP)==1) print Colors[i] } 上面展示了如何通过枚举所有键,然后仅匹配第一个组成索引为 的键来解决此2问题,这意味着键值必须以 开头2,后跟SUBSEP

GNU Awk 示例(类似于Steve 的有用答案,并根据Ed Morton 的评论进行了改进):

GNU Awk 对真正的多维数组的(非标准)支持使得 POSIX 兼容解决方案的不便(大部分)消失了
(但是,GNU Awk 也没有数组初始值设定项):

gawk 'BEGIN {
  Colors[1][""]; split("Red Green Blue", Colors[1])
  Colors[2][""]; split("Yellow Cyan Purple", Colors[2])
  # NOTE: Always use *separate* indices: [1][2] instead of [1,2]
  print Colors[1][2]
  print "---"
  # Enumerate all [2][*] values
  for (i in Colors[2]) print Colors[2][i]
}'
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 重要提示:如上所述,要寻址多维数组中的特定元素,请始终使用单独的索引;例如,[1][2]而不是[1,2]

    • 如果您使用,[1,2]您将获得标准 POSIX 规定的行为,并且您将错误地创建一个带有(字符串连接)值的新的单个索引(键)1 SUBSEP 2
  • split()可以方便地用于直接填充子数组。

  • 然而,作为先决条件,必须初始化二维目标数组:

    • Colors[1][""]Colors[2][""]这样做。
    • 虚拟索引[""]只是用来创建一个二维数组;split()当稍后填充该维度时,它会被丢弃。
  • for (i in ...)支持枚举特定维度:

    • for (i in Colors[2]) ...方便地仅枚举 的子索引Colors[2]