Можно ли добавить элемент в массив в awk без указания индекса?

Я понимаю, что awk имеет ассоциативные массивы, но мне интересно, есть ли эквивалент awk:

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

Очевидным обходным решением является просто сказать:

array[$new_element] = $new_element

Однако это кажется менее читаемым и более хакерским, чем это должно быть.

Ответы

Ответ 1

Я не думаю, что длина массива сразу же доступна в awk (по крайней мере, не в версиях, с которыми я играю). Но вы могли бы просто сохранить длину, а затем сделать что-то вроде этого:

array[arraylen++] = $0;

И затем получите доступ к элементам через одни и те же целочисленные значения:

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

Ответ 2

В gawk вы можете найти длину массива с length(var), поэтому вам не очень сложно приготовить свою собственную функцию.

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

Обратите внимание на это обсуждение: http://objectmix.com/awk/361598-gawk-length-array-question.html - все места, к которым я могу получить доступ, теперь имеют gawk 3.1.5, поэтому я не могу правильно проверить свою функцию, duh, Но вот приближение.

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

Ответ 3

Как говорили другие, awk не предоставляет никаких функций, подобных этому. Ваше "хакерское" обходное решение может работать для некоторых наборов данных, но не для других. Учтите, что вы можете добавить одно и то же значение массива дважды и хотите, чтобы он представлялся дважды в массиве.

$ 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 и что вы никогда не удалите элементы массива, тогда вам может понадобиться тройное предложение A[length(A)+1]="value". Но если вы удалите элемент, ваша следующая запись может перезаписать ваш последний элемент.

Если ваш индекс не имеет значения, и вы не беспокоитесь о том, чтобы тратить пространство на длинные ключи, вы можете использовать случайное число, которое достаточно долго, чтобы уменьшить вероятность столкновений. Быстрая и грязная опция может быть:

srand()
a[rand() rand() rand()]="value"

Не забудьте использовать srand() для лучшей рандомизации и не доверяйте rand() для создания реальных случайных чисел. Это менее совершенное решение несколькими способами, но у него есть преимущество в том, что это одна строка кода.

Если ваши ключи являются числовыми, но, возможно, разреженными, как в примере, который разбил бы решение триплиума, вы можете добавить небольшой поиск к своей функции push:

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

Цикл while гарантирует, что вы присвоите неиспользуемый индекс. Эта функция также совместима с массивами, использующими нечисловые индексы - она ​​назначает ключи, которые являются числовыми, но все равно, что уже есть.

Обратите внимание, что awk не гарантирует порядок элементов в массиве, поэтому идея о том, что вы "нажимаете элемент на конец массива", неверна. Вы добавите этот элемент в массив, но нет гарантии, что он появится последним, когда вы выполните цикл 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