첫 번째 열을 기준으로 그룹화

첫 번째 열을 기준으로 그룹화

다음 패턴의 파일이 있습니다

a 12
a 13
a 15
a 14
b 5
b 6
c 2
c 5

아래와 같이 첫 번째 열을 기준으로 그룹화하고 싶습니다.

a 12 13 15 14
b 5 6
c 2 5

제안해주세요

답변1

데이터가 (질문에서와 같이) 첫 번째 열을 기준으로 정렬되었다고 가정하고 GNU를 사용하여 datamash공백으로 구분된 첫 번째 열을 기준으로 그룹화하고 두 번째 열을 축소합니다.

$ datamash -W groupby 1 collapse 2 <file
a       12,13,15,14
b       5,6
c       2,5

원하는 출력을 얻으려면 결과의 첫 번째 열 뒤의 탭과 쉼표를 공백으로 바꾸십시오.

$ datamash -W groupby 1 collapse 2 <file | tr '\t,' '  '
a 12 13 15 14
b 5 6
c 2 5

입력이 첫 번째 열을 기준으로 정렬되지 않은 경우 sort데이터가 먼저 전달되거나 ( ) 옵션 datamash과 함께 사용됩니다.-s--sort


당신은 또한 사용할 수 있습니다밀러( mlr)그리고 그것의nest작업. 이 함수를 사용하면 두 번째 열의 값을 첫 번째 열의 각 고유 값을 공백으로 구분한 목록으로 "내포"할 수 있습니다.

$ mlr --nidx nest --implode --values --across-records --nested-fs space -f 2 file
a 12 13 15 14
b 5 6
c 2 5

또는 --ivarMiller 버전 5.5.0 이상에서 약어를 사용하십시오(6.0.0 제외).부서진):

$ mlr --nidx nest --ivar space -f 2 file
a 12 13 15 14
b 5 6
c 2 5

데이터를 미리 정렬할 필요는 없습니다.

답변2

사용 awk(입력 파일이 첫 번째 열을 기준으로 정렬된 경우):

awk '{ printf "%s", (NR==1 || pre!=$1? (NR>1? ORS:"")$1: "") OFS $2; pre=$1 }
END  { print "" }' infile

awk+를 사용합니다 sort(입력 파일이 첫 번째 열로 정렬되지 않은 경우).

<infile sort|
    awk '{ printf "%s", (NR==1 || pre!=$1? (NR>1? ORS:"")$1: "") OFS $2; pre=$1 }
    END  { print "" }'

아니면 awk정렬된 입력이나 정렬되지 않은 입력을 사용하세요.

awk '{ grp[$1]= (grp[$1]==""?"":grp[$1] OFS) $2 }
END  { for(x in grp) print x, grp[x] }' infile

답변3

사용행복하다(이전 Perl_6)

raku -e 'lines.map(*.words).map(*.hash).classify( *.keys, :as{$_.values} ).put;'  

입력 예:

a 12
a 13
a 15
a 14
b 5
b 6
c 2
c 5

예제 출력:

a   12 13 15 14
b   5 6
c   2 5

아래는 코딩된 솔루션입니다.행복하다, Perl 프로그래밍 언어 계열의 구성원입니다. 위의 코드는 2열 목록의 (간단한) 사례를 처리합니다(아래에서 보다 일반적인 솔루션에 대한 설명).

보다 일반적인 솔루션(두 개 이상의 열 입력 포함)의 경우 lines행별로 읽고, words합계의 요소를 append해시 로 나누고 %h, =>(굵은 화살표) 해시 생성자를 사용하여 키(왼쪽)와 값(오른쪽)을 묘사합니다. 특수 할당 연산자를 사용하면 .=먼저 별도로 선언하는 단계가 생략됩니다. my %h;그런 다음 hash 를 classify사용하여 반환 값을 기록합니다(그렇지 않으면 전체 키-값 쌍이 반환됩니다).%hkey:as

raku -e 'my %h.=append(.words[0] => .words[1..*]) for lines;  %h.classify(*.keys, :as{$_.values}).put;' 

warpbreaksR 프로그래밍 언어의 데이터(54행, 3열) 와 같은 작은 데이터 세트에 대해 위 코드를 실행합니다. 여기서 두 번째 열은 두 가지 유형의 양모인 " A" 및 " B"을 나타냅니다.

  • [입력 파일은 다음과 같습니다: warpbreakswith를 사용하여 내보낸 데이터 세트, 큰따옴표 제거를 위한 후처리, 쉼표를 탭으로 변환].Rwrite.csvrow.names=FALSE

아래에서 작업 중인 Raku 코드(및 반환)입니다. -ed 키가 아닌 value열을 사용하는 방법(또는 동일 조인을 사용하는 방법)에 유의하세요.join"|"join(",")

~$ raku -e 'my %h.=append(.words[1] => .words[0,2].join("|") ) for lines.skip(1);  %h.classify(*.keys, :as{$_.values}).put;'  warpbreaks_no_quotes.tsv
A   26|L 30|L 54|L 25|L 70|L 52|L 51|L 26|L 67|L 18|M 21|M 29|M 17|M 12|M 18|M 35|M 30|M 36|M 36|H 21|H 24|H 18|H 10|H 43|H 28|H 15|H 26|H
B   27|L 14|L 29|L 19|L 29|L 31|L 41|L 20|L 44|L 42|M 26|M 19|M 16|M 39|M 28|M 21|M 39|M 29|M 20|H 21|H 24|H 17|H 13|H 15|H 15|H 16|H 28|H

https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/warpbreaks.html
https://docs.raku.org/routine/classify
https://raku.org

답변4

awk의 연관 배열을 사용하는 것이 더 쉬운 옵션일 수 있습니다.

$ awk '{k[$1]=k[$1]" "$2} END {for (i in k) print i k[i]}' infile 
a 12 13 15 14
b 5 6
c 2 5

관련 정보