web-dev-qa-db-ja.com

awkで配列の配列を初期化する方法は?

AWKでこのような配列を初期化することは可能ですか?

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

次に、Colors [2,3] = "Purple"の2次元配列を作成します。


別のスレッド 私はそれが不可能であることを理解しています(「残念なことに、split()を乱用せずに一度に配列を設定する方法はありません」)。とにかく、私は100%確信したいと思います、そして、私は同じ質問の他のものがいると確信しています。

上記のような配列を初期化する最も簡単な方法を探していますが、うまく書かれているといいでしょう。

25
BearCode

答えてくれてありがとう。とにかく、一次元配列を初期化したい人のために、ここに例があります:

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

2次元配列は簡単に作成できます。あなたができないことは、私の知る限り、1回の操作で初期化することです。 dmckee のヒントのように、配列を初期化できない理由の1つは、添え字のタイプに制限がないため、純粋な数値である必要がないことです。以下のスクリプトのように、複数の割り当てを行うことができます。添え字は、変数SUBSEPで指定された不明瞭な文字で正式に区切られ、デフォルト値は034(U + 001C、FILE SEPARATOR)です。明らかに、インデックスの1つにこの文字が含まれている場合、混乱が続きます(ただし、文字列でその文字を最後に使用したのはいつですか?)。

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

_GNU awk_がある場合、 true多次元配列 を使用できます。この回答では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
_
10
Steve

既存の回答は役に立ち、すべての側面を網羅していますが、より焦点を絞った要約を提供したいと思いました。

質問は2つの側面を複雑にします。

  • 一般的なAwkでの配列の初期化
  • 特に二次元配列を埋めるために

配列の初期化:

Awkにはno配列リテラル(初期化子)構文があります。

最も単純な回避策は次のとおりです。

  • 単一の文字列として配列要素を表し、
  • 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)
_

2次元配列の初期化:

  • POSIXごとに、Awkにはnotrue多次元配列があります、インデックスが暗黙的に連結されたone-次元配列を使用した、エミュレーションのみビルトイン変数SUBSEPの値を使用して、単一キー(インデックス;allAwk配列に注意してくださいareassociative)です。

    • _arr[1, 2]_は実質的に_arr[1 SUBSEP 2]_と同じです。ここで_1 SUBSEP 2_はキー値を作成するstring concatenationです。
    • 複合キーのフラット配列だけである、本当に複数のディメンションはないため、プライマリ(擬似)ディメンションのすべてのサブインデックスを取得するなど、(擬似)ディメンションをfor (i in ...)で個別に列挙することはできません。 _1_のみ。
    • SUBSEPのデフォルト値は "INFORMATION SEPARATOR ONE"文字 です。これはめったに使用されない制御文字で、日付には表示されません。 in ASCIIおよびUTF-8は、シングルバイト_0x1f_として表されます;必要に応じて、値を変更します。
  • 対照的に、[〜#〜] gnu [〜#〜]Awk、非標準の拡張機能として、doestrue多次元配列をサポートしています。

    • 重要:常にインデックスを指定する必要がありますseparately;たとえば、_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
_

複合キーを使用した1次元配列での多次元配列のエミュレーションには、次のような不便な意味があることに注意してください

  • 補助配列auxArrが必要です。これは、配列の特定の(疑似)次元を直接設定できないためです。

  • one(pseudo-)dimensionをfor (i in ...)で列挙することはできません。allインデックスのみを列挙できます。 (擬似)次元。

    • 上記のfor (i in Colors) { if (index(i, 2 SUBSEP)==1) print Colors[i] }は、allキーを列挙し、最初の構成インデックスが_2_であるキーのみを照合することにより、この問題を回避する方法を示しています。キー値は_2_で始まり、SUBSEPが後に続く必要があります。

[〜#〜] gnu [〜#〜]Awkの例スティーブの有用な答えエド・モートンの コメントで改善):

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

注意:

  • 重要:前述のように、多次元配列の特定の要素をアドレス指定するには、常にseparateを使用しますインデックス;例:_[1][2]_ではなく_[1,2]_。

    • _[1,2]_を使用すると、標準のPOSIXで義務付けられた動作が得られ、誤ってcreate(string-concatenated )値_1 SUBSEP 2_。
  • split()は、サブアレイに直接データを入力するために便利に使用できます。

  • ただし、前提条件として、2次元のターゲット配列を初期化する必要があります。

    • _Colors[1][""]_および_Colors[2][""]_はまさにそれを行います。
    • ダミーインデックス_[""]_は、2次元配列を作成するためのものです。後でsplit()がそのディメンションを埋めると破棄されます。
  • for (i in ...)を使用した特定のディメンションの列挙がサポートされています。

    • for (i in Colors[2]) ...は、便利に_Colors[2]_のサブインデックスのみを列挙します。
3
mklement0

同様のソリューション。 SUBSEP=":"は実際には必要ありません。デモ用に表示可能な文字に設定するだけです:

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
2
TrueY