2011-08-15 36 views
6

Tôi muốn kết hợp các giá trị từ nhiều dòng có độ dài khác nhau thành một dòng nếu chúng khớp với ID.Awk kết hợp nhiều dòng có điều kiện

dụ Input là:

ID: Value: 
a-1 49 
a-2 75 
b-1 120 
b-2 150 
b-3 211 
c-1 289 
d-1 301 
d-2 322 

mong muốn ví dụ đầu ra là:

ID: Value: 
a 49,75 
b 120,150,211 
c 289 
d 301,322 

Làm thế nào tôi sẽ viết một biểu thức awk (hoặc sed hay grep hoặc một cái gì đó) để kiểm tra xem các ID phù hợp, và sau đó in tất cả các giá trị đó vào một dòng? Tôi có thể tất nhiên chỉ cần in chúng vào các cột khác nhau và kết hợp chúng sau này, do đó, thực sự vấn đề chỉ là điều kiện in ấn nếu ID phù hợp và nếu không bắt đầu một dòng mới.

+0

Dòng phần tử 'ID: Value: 'của đầu vào? Bạn có luôn luôn có một '- ' sau ID không? Có một không gian duy nhất, hoặc hai, trong đầu vào? – jfg956

+0

Có đảm bảo rằng tất cả các dòng 'a' sẽ được nhóm lại không? Tôi có nghĩa là, nó có thể là một 'a'-line, sau đó một' b'-line và sau đó một 'a'-line, ví dụ? – brandizzi

+0

Tôi có thể nhóm chúng dễ dàng - dữ liệu thực tế có dạng số có 6 chữ số, tức là 000000-1 000005-1 000005-2 000010-1 000010-2 000010-3 tôi có thể lấy tiêu đề ra và lại thêm nó (mà tôi sẽ làm anyway kể từ khi tôi đang làm lại cột) và dữ liệu được phân tách bằng dấu cách, nhưng có thể dễ dàng thay đổi theo số Cảm ơn –

Trả lời

5

Trong awk, nếu ID của bạn được nhóm với nhau:

awk 'NR==1 {print $0} 
NR > 1 {sub("-.*", "", $1)} 
NR == 2 {prev=$1; printf "%s %s", $1, $2} 
NR > 2 && prev == $1 {printf ",%s", $2} 
NR > 2 && prev != $1 {prev=$1; printf "\n%s %s", $1, $2}' your_input_file 
+0

Cảm ơn rất nhiều - nó hoạt động đẹp –

3

Với đầu vào của bạn:

awk ' 
    NR == 1 {print; next} 
    { 
    split($1,a,/-/) 
    sep = values[a[1]] == "" ? "" : "," 
    values[a[1]] = values[a[1]] sep $2 
    } 
    END {for (key in values) print key, values[key]} 
' 

sản xuất

ID: Value: 
a 49,75 
b 120,150,211 
c 289 
d 301,322 

Một ngôn ngữ hỗ trợ "băm-of-danh sách" sẽ được thuận tiện quá. Dưới đây là một phiên bản Perl

perl -lne ' 
    if ($. == 1) {print; next} 
    if (/^(.+?)-\S+\s+(.*)/) { 
    push @{$values{$1}}, $2; 
    } 
    END { 
    $, = " "; 
    foreach $key (keys %values) { 
    print $key, join(",", @{$values{$key}}); 
    } 
    } 
' 
+0

Việc giữ các id/giá trị trong bộ nhớ mất rất nhiều bộ nhớ nếu tệp lớn. – jfg956

3

Trong sed, giả định các ID được nhóm lại với nhau:

sed -n -e '1p;2{s/-.*//;h};3,${H;x;s/\(.*\) \(.*\)\n\1-.* /\1 \2,/;/\n/{P;s/.*\n//;s/-.*//};x};${x;p}' your_input_file 

Bellow là một nhận xét sed tệp tập lệnh có thể chạy với sed -n -f script your_input_file:

# Print the 1st line as is. 
1p 
# For the 2nd line, remove what is after - in the ID and save in the hold space. 
2{s/-.*//;h} 
# For all the other lines... 
3,${ 
# Append the line to the hold space and place it in the pattern space. 
H;x 
# Substitute identical ids by a ,. 
s/\(.*\) \(.*\)\n\1-.* /\1 \2,/ 
# If we have a \n left in the pattern space, it is a new ID, so print the old and prepare the next. 
/\n/{P;s/.*\n//;s/-.*//} 
# Save what remains in hold space for next line. 
x} 
# For the last line, print what is left in the hold space. 
${x;p} 
+0

Điều đó khá ngọt ngào. Nếu bạn thêm '#!/Usr/bin/sed -nf', bạn có thể chạy nó bằng' script paulmelnikow

+0

Rõ ràng 'awk' phù hợp hơn với nhiệm vụ, nhưng +1 không chỉ cho thấy rằng nó có thể được thực hiện với' sed', mà còn giải thích. –

1

Với đầu vào của bạn trong file INPUT.TXT:

awk '{split($1, a, "-"); hsh[a[1]]=hsh[a[1]]$2","}END{for (i in hsh){print i" "hsh[i]}}' input.txt | sed 's/,$//' 

OUTPUT

a 49,75 
b 120,150,211 
c 289 
d 301,322 
0

Một giải pháp dựa trên công cụ tiêu chuẩn, như là một thay thế cho các giải pháp tuyệt vời cung cấp ở trên ...

$ for INDEX in $(cut -f1 input | uniq); do echo -n "$INDEX ";grep "^$INDEX" input | cut -f2 | tr '\n' ' ';echo; done 
a 49 75 
b 120 150 211 
c 289 
d 301 322 

Sử dụng đầu vào được sửa đổi một chút, không có tiêu đề và chỉ mục, được tạo bằng cách sử dụng

awk 'NR>1' input | sed 's/-[0-9]*//' 
a  49 
a  75 
b  120 
b  150 
b  211 
c  289 
d  301 
d  322 
Các vấn đề liên quan