다음 내용이 포함된 CSV 파일의 텍스트를 조작하는 코드를 작성하고 싶습니다.
71w - Rus,51200
71w - Phi,307200
71w - Ukr,307200
71w - Ukr,51200
71w - Mic,102400
71w - Mic,51200
71w - Jul,256000
71w - Jul,51200
71w - Pro,256000
71w - Uni,51200
71w - Ind,50176
71w - Ind,40960
71w - Sin,358400
71w - May,20480
71w - Tha,512000
71w - Tha,972800
71w - Bar,1280000
71w - Bar,102400
71w - Bar,2048000
71w - Upg,358400
71w - Leg,20480
71w - Res,153600
동일한 값을 가진 열을 수집하여 다음과 같이 해당 행에 배치하고 싶습니다.
71w - Rus,51200
71w - Phi,307200
71w - Ukr,307200,51200
71w - Mic,102400,51200
71w - Jul,256000,51200
71w - Pro,256000
71w - Uni,51200
71w - Ind,50176,40960
71w - Sin,358400
71w - May,20480
71w - Tha,512000,972800
71w - Bar,1280000,102400,2048000
71w - Upg,358400
71w - Leg,20480
71w - Res,153600
감사해요.
답변1
이를 수행하는 좋은 방법은 연관 배열 또는 해시를 사용하는 것입니다. 각 해시의 키는 첫 번째 필드이고(더 나은 용어를 사용하기 위해 "ids"라고 부르겠습니다) 각 키에 저장된 값은 쉼표로 구분된 값을 포함하는 문자열입니다. ID 목록 또는 다음을 포함하는 배열입니다. 같은 내용.
이상한:
이 awk 버전은 배열의 연관 배열로 작업하는 것보다 (awk에서) 더 쉽기 때문에 쉼표로 구분된 문자열을 사용합니다.
#!/usr/bin/awk -f
BEGIN {
FS=" *, *";
OFS="";
}
{
key=$1; $1=""; $0=$0;
if (length(ids[key]) > 0) {
ids[key]=ids[key]","$0;
} else {
ids[key] = $0
};
}
END {
for (k in ids) {
print k "," ids[k]
}
}
Perl에서 배열 해시(또는 "HoA") 작업은 문자열을 연결하는 것보다 어렵지 않습니다(그리고 더 유용하고 유연합니다).
#!/usr/bin/perl -w
use strict;
my %ids = ();
while(<>) {
chomp;
my @F = split /\s*,\s*/;
push @{ $ids{$F[0]} }, $F[1];
};
END {
foreach my $key (keys %ids) {
print $key . ',' . join(",",@{ $ids{$key} }), "\n";
}
}
awk 및 perl 버전의 출력은 동일합니다.
71w - Ukr,307200,51200
71w - Bar,1280000,102400,2048000
71w - Res,153600
71w - Upg,358400
71w - Sin,358400
71w - Mic,102400,51200
71w - May,20480
71w - Tha,512000,972800
71w - Jul,256000,51200
71w - Uni,51200
71w - Ind,50176,40960
71w - Pro,256000
71w - Rus,51200
71w - Leg,20480
71w - Phi,307200
참고: awk 및 perl 버전의 출력은 특별한 순서가 아니며 실행될 때마다 다른 순서로 나타날 수 있습니다. 이는 awk "연관 배열"과 Perl "해시"(동일한 것을 가리키는 두 가지 이름)가 본질적으로 순서가 없기 때문입니다.
sort
필요한 경우 출력을 파이프할 수 있습니다. 또는 Perl에서는 다음을 사용할 수 있습니다.
foreach my $key (sort keys %ids) {
바꾸다:
foreach my $key (keys %ids) {
또한 - 각 ID의 개별 값을 배열에 저장하므로 Perl에서도 값을 쉽게 정렬할 수 있습니다. 예를 들어, END
Perl 버전의 전체 블록을 다음으로 바꾸십시오.
END {
foreach my $key (sort keys %ids) {
print $key . ',' . join(",",sort @{ $ids{$key} }), "\n";
}
}
출력은 다음과 같습니다:
71w - Bar,102400,1280000,2048000
71w - Ind,40960,50176
71w - Jul,256000,51200
71w - Leg,20480
71w - May,20480
71w - Mic,102400,51200
71w - Phi,307200
71w - Pro,256000
71w - Res,153600
71w - Rus,51200
71w - Sin,358400
71w - Tha,512000,972800
71w - Ukr,307200,51200
71w - Uni,51200
71w - Upg,358400
답변2
GNU 사용 datamash
:
$ datamash -t, -g 1 collapse 2 < file.csv
71w - Rus,51200
71w - Phi,307200
71w - Ukr,307200,51200
71w - Mic,102400,51200
71w - Jul,256000,51200
71w - Pro,256000
71w - Uni,51200
71w - Ind,50176,40960
71w - Sin,358400
71w - May,20480
71w - Tha,512000,972800
71w - Bar,1280000,102400,2048000
71w - Upg,358400
71w - Leg,20480
71w - Res,153600
정렬된 출력 사용 -s
:
$ datamash -s -t, -g 1 collapse 2 < file.csv
71w - Bar,1280000,102400,2048000
71w - Ind,50176,40960
71w - Jul,256000,51200
71w - Leg,20480
71w - May,20480
71w - Mic,102400,51200
71w - Phi,307200
71w - Pro,256000
71w - Res,153600
71w - Rus,51200
71w - Sin,358400
71w - Tha,512000,972800
71w - Ukr,307200,51200
71w - Uni,51200
71w - Upg,358400
옵션 설명:
-s
그룹화하기 전에 입력 정렬-t,
필드 구분 기호로 쉼표 사용-g 1
첫 번째 필드의 그룹collapse 2
두 번째 필드에서 충돌
"충돌" 예를 살펴보세요수동.
답변3
입력이 정렬 등을 통해 입력에 표시된 $1 값으로 그룹화되거나 그룹화될 수 있다고 가정합니다.
$ cat tst.awk
BEGIN { FS=OFS="," }
$1 != prev { if (NR>1) print rec; rec=prev=$1 }
{ rec = rec OFS $2 }
END { print rec }
.
$ awk -f tst.awk file
71w - Rus,51200
71w - Phi,307200
71w - Ukr,307200,51200
71w - Mic,102400,51200
71w - Jul,256000,51200
71w - Pro,256000
71w - Uni,51200
71w - Ind,50176,40960
71w - Sin,358400
71w - May,20480
71w - Tha,512000,972800
71w - Bar,1280000,102400,2048000
71w - Upg,358400
71w - Leg,20480
71w - Res,153600
또는 명확성보다 간결함을 선호하는 경우:
$ awk -F, '$1!=p{if(NR>1)print r;r=p=$1}{r=r FS$2}END{print r}' file
71w - Rus,51200
71w - Phi,307200
71w - Ukr,307200,51200
71w - Mic,102400,51200
71w - Jul,256000,51200
71w - Pro,256000
71w - Uni,51200
71w - Ind,50176,40960
71w - Sin,358400
71w - May,20480
71w - Tha,512000,972800
71w - Bar,1280000,102400,2048000
71w - Upg,358400
71w - Leg,20480
71w - Res,153600