web-dev-qa-db-ja.com

インデックスを指定せずにawkの配列にアイテムを追加することは可能ですか?

Awkには連想配列があることはわかっていますが、これに相当するawkがあるかどうか疑問に思います。

http://php.net/manual/en/function.array-Push.php

明らかな回避策は、次のように言うことです。

array[$new_element] = $new_element

ただし、これは必要以上に読みにくく、ハックっぽいようです。

20
merlin2011

配列の長さがawkですぐに利用できるとは思いません(少なくとも私がいじくり回しているバージョンでは)。しかし、単に長さを維持してから、次のようなことを行うことができます。

array[arraylen++] = $0;

次に、同じ整数値を介して要素にアクセスします。

for ( i = 0; i < arraylen; i++ )
   print array[i];
12
Mark Wilkins

gawkではlength(var)で配列の長さを見つけることができるので、独自の関数を作成するのはそれほど難しくありません。

function Push(A,B) { A[length(A)+1] = B }

ただし、この議論に注意してください。 http://objectmix.com/awk/361598-gawk-length-array-question.html -現在アクセスできるすべての場所にgawk3.1.5があるので機能を適切にテストできません。しかし、ここに概算があります。

vnix$ gawk '# BEGIN: make sure arr is an array
>   BEGIN { delete arr[0] }
>   { print "=" length(arr); arr[length(arr)+1] = $1;
>     print length(arr), arr[length(arr)] }
>   END { print "---";
>     for (i=1; i<=length(arr); ++i) print i, arr[i] }' <<HERE
> fnord foo
> ick bar
> baz quux
> HERE
=0
1 fnord
=1
2 ick
=2
3 baz
---
1 fnord
2 ick
3 baz
9
tripleee

他の人が言っているように、awkは箱から出してこのような機能を提供しません。 「ハック」回避策は、一部のデータセットでは機能する場合がありますが、他のデータセットでは機能しない場合があります。同じ配列値を2回追加し、それを配列内で2回表現したい場合があることを考慮してください。

_$ echo 3 | awk 'BEGIN{ a[1]=5; a[2]=12; a[3]=2 }
>   { a[$1] = $1 }
>   END {print length(a) " - " a[3]}'
3 - 3
_

最良の解決策は、データが配列にあることでわかるかもしれませんが、ここにいくつかの考えがあります。

まず、インデックスが常に数値であり、常に1から始まり、配列要素を削除しないことが確実な場合は、tripleのA[length(A)+1]="value"の提案が役立つ可能性があります。ただし、要素を削除すると、次の書き込みで最後の要素が上書きされる可能性があります。

インデックスが重要でない場合、長いキーでスペースを浪費する心配がない場合は、衝突の可能性を減らすのに十分な長さの乱数を使用できます。迅速で汚いオプションは次のとおりです。

_srand()
a[Rand() Rand() Rand()]="value"
_

ランダム化を改善するためにsrand()を使用することを忘れないでください。また、実際の乱数を生成するためにRand()を信頼しないでください。これは多くの点で完全ではないソリューションですが、1行のコードであるという利点があります。

キーが数値であるがスパースである可能性がある場合トリプリーのソリューションを破る例のように、プッシュ関数に小さな検索を追加できます。

_function Push (a, v,     n) {
  n=length(a)+1
  while (n in a) n++
  a[n]=v
}
_

Whileループは、未使用のインデックスを割り当てることを保証します。この関数は、数値以外のインデックスを使用する配列とも互換性があります-数値であるitassignsキーですが、すでに存在するものは関係ありません。

Awkは配列内の要素の順序を保証しないため、「アイテムを配列の最後にプッシュする」という考えは間違っていることに注意してください。この要素を配列にaddしますが、forループをステップスルーしたときに最後に表示される保証はありません。

_$ cat a
#!/usr/bin/awk -f

function Push (a, v,     n) {
  n=length(a)+1
  while (n in a) n++
  a[n]=v
}

{
  Push(a, $0)
}

END {
  print "length=" length(a)
  for(i in a) print i " - " a[i]
}

$ printf '3\nfour\ncinq\n' | ./a
length=3
2 - four
3 - cinq
1 - 3
_
1
ghoti