2013-05-03 6 views
0

다음 표는 조작하려는 데이터의 간단한 스냅 샷을 보여줍니다. 유사한 요소를 하나의 그룹으로 묶을 awk 스크립트를 찾고 있습니다. 예를 들면. 아래 표를 보면 :awk를 사용하여 공통 요소 그룹화

  1. 숫자 (1,2,3,4,6)는 모두 하나의 그룹에 속해야합니다. 따라서 행 1 행 2 행 4 행 8은 그룹 "1"이됩니다.
  2. 9 번은 고유하며 공통 요소가 없습니다.

    heading1  heading2   numberlist  group 
    name1   text    1,2,3   1 
    name2   text    2    1 
    name3   text    9    2 
    name4   text    1,4   1 
    name5   text    5,7   3 
    name6   text    7    3 
    name7   text    8    4 
    name8   text    6,2   1 
    

    : 그래서 3 군 말할 등등 ...

파일이

  • 이 유사 번호 5,7 하나 개의 그룹에 상주 할 그룹을 말한다 별도의 그룹에 혼자있는 것 내 검색어와 비슷한 검색어를 찾고 있었는데이 링크를 찾았습니다. Grouping lists by common elements. 그러나 해결책은 C++에서 awk가 아니라, 이것이 나의 주요 요구 사항이다.

    덧붙여 말하자면이 awk 솔루션은 내 쿼리와 다소 관련이 있지만 쉼표로 구분 된 값을 처리하지 않았습니다. awk script grouping with array

    숫자 목록, 즉 $ 3은 그룹화를위한 유일한 고려 사항입니다.

    split이 첫 번째 분할 :

  • 답변

    0

    [[bash_prompt$]]$ cat log ; echo "########"; \ 
    > cat test.sh ;echo "########"; awk -f test.sh log 
    heading1  heading2   numberlist  group 
    name1   text    1,2,3 
    name2   text    2 
    name3   text    9 
    name4   text    1,4 
    name5   text    5,7 
    name6   text    7 
    name7   text    8 
    name8   text    6,2 
    ######## 
    /^name/{ 
        i=0; j=0; 
        split($3,a,","); 
        for(var in a) { 
        for(var1 in q) { 
         split(q[var1],r,","); 
         for(var2 in r) { 
         if(r[var2] == a[var]) { 
          i=1; 
          j=((var1+1)); 
         } 
         } 
        } 
        } 
        if(i == 0) { 
         q[length(q)] = $3; 
         j=length(q); 
        } 
        print $1 "\t\t" $2 " \t\t" $3 "\t\t" j; 
    } 
    ######## 
    name1   text   1,2,3   1 
    name2   text   2    1 
    name3   text   9    2 
    name4   text   1,4    1 
    name5   text   5,7    3 
    name6   text   7    3 
    name7   text   8    4 
    name8   text   6,2    1 
    [[bash_prompt$]]$ 
    

    업데이트 ...이 문제는 내 문제 중 하나가 거의 같은 듯 나는 내 문제를 해결하기 위해 예를 하나 개의 컬럼을 사용했다 :) 그래서 인수를 세 번째 인수에서 전달 된 구분 기호로 분리하여 두 번째 인수가 가리키는 배열에 넣습니다. 여기서 main 배열은 그룹의 그룹 멤버를 담고있는 q입니다. 기본적으로 요소의 인덱스가 그룹 id이고 요소가 그룹의 모든 멤버 인 배열의 배열입니다. 따라서 q[0]="1,2,3"은 0 번째 그룹이 1, 23 멤버를 포함하고 있음을 나타냅니다. 이제 awk에서 name (/^name/)으로 시작하는 처음 한 줄을 읽습니다. 그런 다음 세 번째 필드 (1,2,3)는 배열로 나뉩니다. 이제 배열 a의 각 요소에 대해 q (for(var1 in q))에 저장된 각 그룹에 대해 각 그룹 내에서 다른 임시 배열 r (split(q[var1],r,","))으로 분할합니다. 즉 "1,2,3"은 배열 r. 이제 r의 각 요소가 a의 요소와 비교됩니다. 일치하는 것이 발견되면 그룹의 인덱스는 해당 행의 인덱스입니다 (배열 인덱스는 0부터 시작하고 그룹의 인덱스는 1부터이므로 ((var1 + 1)). 찾지 못하면 q의 새 그룹으로 추가하고 마지막 인덱스 + 1 어레이 즉 길이는 행 인덱스이고

    업데이트 :

    /^name/{ 
        j=0; 
        split($3,a,","); 
        for(var in a) { 
        if(q[a[var]] != 0) { 
         j=q[a[var]]; i=1; 
         break; 
        } 
        } 
        j = (j == 0) ? ++k : j; 
        for(var1 in a) { 
        if(q[a[var1]] == 0) { 
         q[a[var1]] = j; 
        } 
        } 
        print $1 "\t\t" $2 " \t\t" $3 "\t\t" j; 
    } 
    

    업데이트 :

    베이스 AWK가 결합 배열을 갖고, 각 요소는 문자열 액세스 이전 방법은 키가 그룹의 인덱스 인 배열에 각 그룹을 저장하는 것이 었습니다. 그래서 우리가 칼럼을 읽을 때, 우리는 각 그룹을 읽고, 개별 요소로 그룹을 나누고, comp 각 열의 각 요소가있는 요소입니다. 그러나 그룹을 저장하는 대신 배열에 요소를 저장하는 경우 key는 요소 자체이고 key의 값은 요소가 속한 그룹의 인덱스입니다.그래서 열을 읽을 때 개별 요소 (split($3,a,",");)의 열을 분할 한 다음 요소가 키로 그룹 인덱스가있는 경우 배열의 요소를 검사합니다 (awk에서는 요소가 없으면 기본적으로 요소 값 0이 거기에서 초기화되므로 체크 q[a[var]] != 0). 요소가 발견되면 요소의 그룹 색인을 열의 색인으로 사용하고 중단합니다. 그렇지 않으면 j은 0으로 유지됩니다. j이 0이면 ++k은 최신 그룹 색인을 제공합니다. 이제 우리는 컬럼 요소에 대한 그룹 인덱스를 발견했습니다. 다른 그룹의 일부가 아닌 요소에 해당 색인을 전달해야합니다 (동일한 열에있는 여러 요소가 다른 그룹에 속하는 경우가 있습니다. 여기서는 선착순 방식이지만 서술하지 않습니다. 이미 다른 그룹에 속한 다른 그룹의 인덱스). 따라서 열 (for(var1 in a))의 각 요소에 대해 그룹 (if(q[a[var1]] == 0))에 속하지 않으면 그룹 색인 q[a[var1]] = j;을 지정하십시오. 그래서 우리는 엘리먼트를 직접적으로 키를 사용하여 액세스하기 때문에 모든 액세스가 선형입니다. 따라서 모든 요소에 대해 반복해서 그룹을 나누어서는 안되며 그러므로 더 짧은 시간. 나의 첫 번째 접근 방식은 좀 더 복잡한 처리이지만 더 짧은 데이터 세트 인 내 자신의 문제 (첫 번째 줄에서 언급 했음) 중 하나를 기반으로했습니다. 그러나 이것은 더 간단한 직선적 인 논리를 필요로했습니다.

    +0

    감사합니다. abasu. 솔루션은 매력처럼 작동했습니다. 이것은 처리 할 데이터의 작은 스냅 샷일뿐입니다. 실제 데이터는 20 백만 항목에 가깝습니다. 압력에 견딜 것이라고 기대하고 있습니다. 나는 시험을하고 당신에게 알려줄 것입니다. 그 동안 코드를 문서화 할 수 있습니까? 내부 루프를 이해하는 것은 다소 까다 롭습니다. – user676500

    +0

    업데이트되었습니다. 작동 중이면 승인으로 표시하고, 그렇지 않으면 알려주십시오. 큰 데이터 세트가 실행중인 경우, 일치를 발견하면'break'를 사용하여 런타임을 단축합니다. – abasu

    +0

    예. 다시 한번 감사드립니다. – user676500