2010-06-17 2 views
13

Awk предлагает ассоциативную индексацию для обработки массивов. Элементы 1-мерной матрицы можно повторить:Итерация массива Awk для многомерных массивов

например.

for(index in arr1) 
    print "arr1[" index "]=" arr1[index] 

Но как этот вид выполнен для двухмерного массива? Используется ли синтаксис, приведенный ниже?

for(index1 in arr2) 
for(index2 in arr2) 
    arr2[index1,index2]  
+0

'gawk' as of v4 поддерживает массивы как элементы, т.е. вложенные массивы, более гибкие, чем многомерные массивы,' for (i в arr2) для (j в arr2 [i]) print arr2 [i] [j] ', см. [Ответ JJoao] (http://stackoverflow.com/a/35891319/1290731) – jthill

ответ

29

AWK подделывает многомерные массивы, объединяя индексы с символом, содержащимся в переменной SUBSEP (0x1c). Вы можете перемещаться с помощью двумерного массива с использованием split, как это (основано на примере в файле info gawk):

awk 'BEGIN { OFS=","; array[1,2]=3; array[2,3]=5; array[3,4]=8; 
    for (comb in array) {split(comb,sep,SUBSEP); 
    print sep[1], sep[2], array[sep[1],sep[2]]}}' 

Выход:

2,3,5 
3,4,8 
1,2,3 

Вы можете, однако, перебрать численно индексированный массив с использованием вложенных циклов для:

for (i = 1; i <= width; i++) 
    for (j = 1; j < = height; j++) 
     print array[i, j] 

Еще одним примечательных немного информации из GAWK manual:

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

 (subscript1, subscript2, ...) in array 
5

Нет, синтаксис

for(index1 in arr2) for(index2 in arr2) { 
    print arr2[index1][index2]; 
} 

не будет работать. Awk действительно не поддерживает многомерные массивы. Что она делает, если вы делаете что-то вроде

x[1,2] = 5; 

является конкатенация двух индексов (1 & 2), чтобы сделать строку, разделенных значением переменной SUBSEP. Если это равно «*», то вы бы иметь такой же эффект, как

x["1*2"] = 5; 

Значение по умолчанию SUBSEP не является символом печати, что соответствует Ctrl + \. Вы можете увидеть это с помощью следующего сценария:

BEGIN { 
    x[1,2]=5; 
    x[2,4]=7; 
    for (ix in x) { 
     print ix; 
    } 
} 

Запуск этого дает:

% awk -f scriptfile | cat -v 
1^\2 
2^\4 

Так, в ответ на ваш вопрос - как перебрать многомерный массив - использовать только один for(a in b) цикл , но вам может потребоваться дополнительная работа по разделению a в его x и y частях.

3

Текущие версии поглазеть (ГНУ AWK, по умолчанию в Linux, и можно установить везде, где вы want), имеет реальные многомерные массивы.

for(b in a) 
    for(c in a[b]) 
     print a[b][c], c , b 

См также функцию isarray()

1

я приведу пример того, как я использую это в моих данных запроса обработки работы. Предположим, у вас есть файл экстракт полный сделок по категориям продукции и идентификатор клиента:

customer_id category sales 
1111   parts  100.01 
1212   parts  5.20 
2211   screws  1.33 
...etc... 

Его легко использовать AWK подсчитать общее количество различных клиентов с покупкой:

awk 'NR>1 {a[$1]++} END {for (i in a) total++; print "customers: " total}' \ 
datafile.txt 

Однако вычисления количества различные клиенты с покупкой в ​​каждой категории предполагает двухмерного массив:

awk 'NR>1 {a[$2,$1]++} 
     END {for (i in a) {split(i,arr,SUBSEP); custs[arr[1]]++} 
      for (k in custs) printf "category: %s customers:%d\n", k, custs[k]}' \ 
datafile.txt 

приращение custs[arr[1]]++ работ, потому что каждая категория/Параметр client_id уникален как индекс для ассоциативного массива, используемого awk.

По правде говоря, я использую gnu awk, который работает быстрее и может делать array[i][j], как упоминал Д. Уильямсон. Но я хотел быть уверенным, что смогу сделать это в стандартном awk.

1

awk (1) был первоначально разработан - частично - для обучения инструменту для языка C, а многомерные массивы были как в C, так и в awk (1) навсегда. как таковой POSIX IEEE 1003.2 стандартизировал их.

Чтобы изучить синтаксис и семантику, если вы создаете следующий файл с именем «test.awk»:

BEGIN { 
    KEY["a"]="a"; 
    KEY["b"]="b"; 
    KEY["c"]="c"; 
    MULTI["a"]["test_a"]="date a"; 
    MULTI["b"]["test_b"]="dbte b"; 
    MULTI["c"]["test_c"]="dcte c"; 
} 
END { 
    for(k in KEY) { 
    kk="test_" k ; 
    print MULTI[k][kk] 
    } 
    for(q in MULTI) { 
    print q 
    } 
    for(p in MULTI) { 
    for(pp in MULTI[p]) { 
     print MULTI[p][pp] 
    } 
    } 
} 

и запустить его с помощью этой команды:

awk -f test.awk /dev/null 

вы получите следующее выход:

date a 
dbte b 
dcte c 
a 
b 
c 
date a 
dbte b 
dcte c 

по крайней мере на Linux Mint 18 Cinnamon 64-битный 4.4.0-21-родовой # 37-Ubuntu SMP

Смежные вопросы