繁体   English   中英

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

[英]How to initialize an array of arrays in awk?

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

Colors[1] = ("Red", "Green", "Blue")
Colors[2] = ("Yellow", "Cyan", "Purple")

然后有一个二维数组,其中Colors [2,3] =“Purple”。


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

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

您可以轻松地创建二维数组。 你不能做的,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];
}

示例运行:

$ 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
$

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

SColors = "Red_Green_Blue"
split(SColors, Colors, "_")
print Colors[1] " - " Colors[2] " - " Colors[3]

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

awk -f script.awk

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

结果:

Purple

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

这个问题涉及两个方面:

  • 通常在Awk中初始化数组
  • 这样做可以特别填充二维数组

数组初始化:

awk 没有数组文字(初始化)语法。

最简单的解决方法是:

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

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

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

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

初始化二维数组:

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

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

    • 重要提示 :您必须始终单独指定索引; 例如,你必须使用arr[1][2]代替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

注意,使用复合键对具有一维阵列的多维阵列进行仿真具有以下不方便的含义

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

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

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

GNU Awk示例 (类似于史蒂夫的有用答案 ,改进了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]
}'

注意:

  • 重要提示 :如上所述,要解决多维数组中的特定元素,请始终使用单独的索引; 例如, [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]

类似的解决方案。 SUBSEP=":"并不是真的需要,只需设置为任何可见的char用于演示:

awk 'BEGIN{SUBSEP=":"
split("Red Green Blue",a); for(i in a) Colors[1,i]=a[i];
split("Yellow Cyan Purple",a); for(i in a) Colors[2,i]=a[i];
for(i in Colors) print i" => "Colors[i];}'

或者更隐蔽的版本:

awk 'BEGIN{SUBSEP=":"
split("Red Green Blue Yellow Cyan Purple",a); 
for(i in a) Colors[int((i-1)/3)+1,(i-1)%3+1]=a[i];
for(i in Colors) print i" => "Colors[i];}'

输出:

1:1 => Red
1:2 => Green
1:3 => Blue
2:1 => Yellow
2:2 => Cyan
2:3 => Purple

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM