如何在awk中复制多维数组(即数组的数组)? [英] How do you copy a multi-dimensional array (i.e. an array of arrays) in awk?

查看:194
本文介绍了如何在awk中复制多维数组(即数组的数组)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

该问题的目的是针对非显而易见的解决方案发布问题的规范答案-复制数组数组(需要GNU awk才能获取数组数组).

The intent of this question is to post a canonical answer to a problem with a non-obvious solution - copying arrays of arrays (requires GNU awk for arrays of arrays).

给出数组数组,例如有关遍历数组:

Given an array of arrays such as shown in the gawk manual on the section about traversing arrays:

BEGIN {
    a[1] = 1
    a[2][1] = 21
    a[2][2] = 22
    a[3] = 3
    a[4][1][1] = 411
    a[4][2] = 42

    walk_array(a, "a")
}

function walk_array(arr, name,      i)
{
    for (i in arr) {
        if (isarray(arr[i]))
            walk_array(arr[i], (name "[" i "]"))
        else
            printf("%s[%s] = %s\n", name, i, arr[i])
    }
}

您将如何编写一个copy_array函数,该函数可以处理数组数组以将现有数组复制到新数组,以便对新复制的数组的walk_array()后续调用将为新数组输出相同的值至于原始的,即这样:

how would you write a copy_array function that can handle arrays of arrays to copy an existing array to a new array such that a subsequent call to walk_array() for the newly copied array would output the same values for the new array as for the original, i.e. so that this:

BEGIN {
    a[1] = 1
    a[2][1] = 21
    a[2][2] = 22
    a[3] = 3
    a[4][1][1] = 411
    a[4][2] = 42

    walk_array(a, "a")

    copy_array(a, b)

    print "----------"

    walk_array(b, "b")
}

将输出:

a[1] = 1
a[2][1] = 21
a[2][2] = 22
a[3] = 3
a[4][1][1] = 411
a[4][2] = 42
----------
b[1] = 1
b[2][1] = 21
b[2][2] = 22
b[3] = 3
b[4][1][1] = 411
b[4][2] = 42

推荐答案

$ cat tst.awk
BEGIN {
    a[1] = 1
    a[2][1] = 21
    a[2][2] = 22
    a[3] = 3
    a[4][1][1] = 411
    a[4][2] = 42

    walk_array(a, "a")

    copy_array(a, b)

    print "----------"

    walk_array(b, "b")
}

function copy_array(orig, copy,      i)
{
    delete copy         # Empty "copy" for first call and delete the temp
                        # array added by copy[i][1] below for subsequent.
    for (i in orig) {
        if (isarray(orig[i])) {
            copy[i][1]  # Force copy[i] to also be an array by creating a temp
            copy_array(orig[i], copy[i])
        }
        else {
            copy[i] = orig[i]
        }
    }
}

function walk_array(arr, name,      i)
{
    for (i in arr) {
        if (isarray(arr[i]))
            walk_array(arr[i], (name "[" i "]"))
        else
            printf("%s[%s] = %s\n", name, i, arr[i])
    }
}

.

$ awk -f  tst.awk
a[1] = 1
a[2][1] = 21
a[2][2] = 22
a[3] = 3
a[4][1][1] = 411
a[4][2] = 42
----------
b[1] = 1
b[2][1] = 21
b[2][2] = 22
b[3] = 3
b[4][1][1] = 411
b[4][2] = 42

在内部调用copy_array()之前使用copy[i][1]创建临时数组,然后在进入copy_array()时将其删除,这是为了避免随后的代码假定copy[i]处存在的是标量-这与使用split()(内部首先删除作为参数传递的arry)在创建子数组之前必须创建临时数组的方式相同,因为假定数组元素的内容为标量默认情况下是为了与为不支持数组数组的awks(例如POSIX awks)编写的代码向后兼容:

The use of copy[i][1] to create a temp array before the internal call to copy_array() which is then deleted on entry to copy_array() is to avoid the subsequent code from assuming that what exists at copy[i] is a scalar - this is the same as how you have to create a temp array before using split() (which internally first deletes the arry you pass as an argument) to populate a subarray because the content of an array element is assumed to be a scalar by default for backward compatibility with code written for awks that do not support arrays of arrays (e.g. POSIX awks):

$ printf 'a b\nc d\n' |
  awk '{split($0,arr[NR])} END{for (i in arr) for (j in arr[i]) print i,j,arr[i][j]}'
awk: cmd. line:1: (FILENAME=- FNR=1) fatal: split: second argument is not an array

$ printf 'a b\nc d\n' |
  awk '{arr[NR][1]; split($0,arr[NR])} END{for (i in arr) for (j in arr[i]) print i,j,arr[i][j]}'
1 1 a
1 2 b
2 1 c
2 2 d

这篇关于如何在awk中复制多维数组(即数组的数组)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆