텍스트 조작 - 값을 기준으로 열을 행으로 바꿉니다.

텍스트 조작 - 값을 기준으로 열을 행으로 바꿉니다.

다음 내용이 포함된 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에서도 값을 쉽게 정렬할 수 있습니다. 예를 들어, ENDPerl 버전의 전체 블록을 다음으로 바꾸십시오.

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

관련 정보