Можно ли добавить элемент в массив в 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