2010-06-17 30 views
13

Awk cung cấp chỉ mục liên kết để xử lý mảng. Các phần tử của mảng 1 chiều có thể được lặp lại:Lặp lại mảng awk cho mảng đa chiều

ví dụ:

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

Nhưng loại này được thực hiện cho mảng hai chiều như thế nào? Có loại cú pháp, đưa ra dưới đây làm việc?

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

'gawk' như v4 hỗ trợ mảng như phần tử tức là mảng lồng nhau, linh hoạt hơn mảng đa chiều,' cho (i trong arr2) cho (j trong arr2 [i]) in arr2 [i] [j] ', xem [Câu trả lời của JJoao] (http://stackoverflow.com/a/35891319/1290731) – jthill

Trả lời

29

AWK giả mạo mảng đa chiều bằng cách nối các chỉ mục với ký tự được giữ trong biến SUBSEP (0x1c). Bạn có thể lặp qua một mảng hai chiều sử dụng split như thế này (dựa trên một ví dụ trong file 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]]}}' 

Output:

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

Bạn có thể, tuy nhiên, lặp trên một số lượng lập chỉ mục mảng bằng cách sử dụng lồng nhau cho vòng:

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

Một chút đáng chú ý của thông tin từ GAWK manual:

Để kiểm tra xem chuỗi chỉ mục cụ thể có tồn tại trong mảng đa chiều hay không, hãy sử dụng cùng toán tử (in) được sử dụng cho mảng một chiều. Viết toàn bộ chuỗi các chỉ số trong ngoặc đơn, cách nhau bằng dấu phẩy, như các toán hạng trái:

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

Không, cú pháp

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

sẽ không hoạt động. Awk không thực sự hỗ trợ mảng đa chiều. Những gì nó làm, nếu bạn làm điều gì đó như

x[1,2] = 5; 

là để nối hai chỉ số (1 & 2) để thực hiện một chuỗi, cách nhau bằng các giá trị của biến SUBSEP. Nếu đây là bằng "*", sau đó bạn muốn có tác dụng tương tự như

x["1*2"] = 5; 

Giá trị mặc định của SUBSEP là một nhân vật phi in ấn, tương ứng với tổ hợp phím Ctrl + \. Bạn có thể thấy điều này với kịch bản sau đây:

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

Chạy điều này mang lại:

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

Vì vậy, trong câu trả lời cho câu hỏi của bạn - làm thế nào để lặp một mảng đa chiều - chỉ cần sử dụng một for(a in b) vòng lặp đơn , nhưng bạn có thể cần thêm một số công việc để chia nhỏ a thành các phần xy của chúng tôi.

3

Các phiên bản hiện tại của trố mắt (các awk gnu, mặc định trong Linux, và có thể cài đặt ở khắp mọi nơi bạn muốn), có các mảng đa chiều thực.

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

Xem thêm hoạt isarray()

1

tôi sẽ cung cấp một ví dụ về cách tôi sử dụng này trong truy vấn dữ liệu xử lý công việc của tôi. Giả sử bạn có một tập tin giải nén đầy đủ các giao dịch bằng loại sản phẩm và id khách hàng:

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

của nó dễ dàng để sử dụng awk để đếm tổng số khách hàng riêng biệt với mua hàng:

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

Tuy nhiên, tính toán số lượng khách hàng khác biệt với giao dịch mua trong mỗi danh mục cho thấy mảng hai chiều:

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 

Tăng thêm custs[arr[1]]++ hoạt động vì mỗi danh mục/custo cặp mer_id là duy nhất như một chỉ mục cho mảng kết hợp được sử dụng bởi awk.

Thật ra, tôi sử dụng gnu awk nhanh hơn và có thể làm array[i][j] như D. Williamson đã đề cập. Nhưng tôi muốn chắc chắn rằng tôi có thể làm điều này trong tiêu chuẩn awk.

1

awk (1) ban đầu được thiết kế - một phần - là công cụ giảng dạy cho ngôn ngữ C, và mảng đa chiều đã ở cả C và awk (1) khá nhiều mãi mãi. như POSIX IEEE 1003.2 đã tiêu chuẩn hóa chúng.

Để khám phá cú pháp và ngữ nghĩa, nếu bạn tạo ra các tập tin sau đây được gọi là "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] 
    } 
    } 
} 

và chạy nó với lệnh này:

awk -f test.awk /dev/null 

bạn sẽ nhận được như sau đầu ra:

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

ít nhất trên Linux Mint 18 Quế 64-bit 4.4.0-21-generiC# 37-Ubuntu SMP