vlookup using awk: how to match groups/patterns with ids

Viewed 74

I am using awk and want to do vlookup kind of thing for a group pattern which matches the ids of the master list

master.txt

1.1.1: name00
1.1.2: name01
1.1.3: name02
1.1.4: name03
1.1.5: name04
1.2.2: name05
1.2.3: name06
1.2.4: name07
1.2.5: name08
1.2.6: name09
1.3.13: name10
1.3.14: name11
1.3.15: name12
1.3.16: name13
1.3.17: name14

group.txt

1.1: groupvalue0
1.2: groupvalue1
1.3: groupvalue2
1.1: groupvalue10
1.3: groupvalue12

each group can have multiple values

Corresponding master data for group 1.1: here (^1.1.) matches the below (matching from beginning only)

1.1.1: name00
1.1.2: name01
1.1.3: name02
1.1.4: name03
1.1.5: name04

similarly for 1.2 here (^1.2.) matches the below (matching from beginning only)

1.2.2: name05
1.2.3: name06
1.2.4: name07
1.2.5: name08
1.2.6: name09

Based on the matching i want the result as

name00: groupvalue0  # 1.1.1 just shown for reference
name01: groupvalue0  # 1.1.2 just shown for reference
name02: groupvalue0  # 1.1.3 just shown for reference
name03: groupvalue0  # 1.1.4 just shown for reference
name04: groupvalue0  # 1.1.5 just shown for reference
name05: groupvalue1  # 1.2.2 just shown for reference
name06: groupvalue1  # 1.2.3 just shown for reference
name07: groupvalue1  # 1.2.4 just shown for reference
name08: groupvalue1  # 1.2.5 just shown for reference
name09: groupvalue1  # 1.2.6 just shown for reference
name10: groupvalue2  # 1.3.13 just shown for reference
name11: groupvalue2  # 1.3.14 just shown for reference
name12: groupvalue2  # 1.3.15 just shown for reference
name13: groupvalue2  # 1.3.16 just shown for reference
name14: groupvalue2  # 1.3.17 just shown for reference
name00: groupvalue10  # 1.1.1 just shown for reference
name01: groupvalue10  # 1.1.2 just shown for reference
name02: groupvalue10  # 1.1.3 just shown for reference
name03: groupvalue10  # 1.1.4 just shown for reference
name04: groupvalue10  # 1.1.5 just shown for reference
name10: groupvalue12  # 1.3.13 just shown for reference
name11: groupvalue12  # 1.3.14 just shown for reference
name12: groupvalue12  # 1.3.15 just shown for reference
name13: groupvalue12  # 1.3.16 just shown for reference
name14: groupvalue12  # 1.3.17 just shown for reference

I am trying to use the below awk code. but how to use pattern in arrays.

BEGIN{
    FS=": "
    #print(var)
}
{ 
  if(NR==FNR)         # process first file only
  {                    
    a[$1]=$2;           # hash to a array {id is key, name} value
    next;               # process next record without executing following code
  } else
  {                    # process second file
    pattern= "^"$1"\..*" # eg: ^1\.1\..*
    # can i use pattern in array
    print a[pattern]":",$2  # output name (the value of) from array a and property
  }

} master.txt group.txt
3 Answers

EDIT1: Since OP has changed question a bit adding the solution as per that here.

awk '
BEGIN{
  OFS=":"
}
FNR==NR{
  a[$1]=(a[$1]?a[$1]",":"")$2
  next
}
{
  sub(/\.[0-9]+:/,OFS,$1)
  key=$1
}
(key in a){
  delete array
  num=split(a[key],array,",")
  for(i=1;i<=num;i++){
    printf("%s%s",$2 OFS " "array[i],i==num?ORS:" ")
  }
}
' groups.txt masters.txt


Could you please try following, written and tested with shown samples.

awk '
FNR==NR{
  a[$1]=$2
  next
}
{
  key=substr($0,1,3)":"
}
(key in a){
  print $2":\t"a[key]
}
' groups.txt masters.txt

Explanation: Adding detailed explanation for above.

awk '                         ##Starting awk program from here.
FNR==NR{                      ##Checking condition if FNR==NR which will be TRUE when groups.txt is being read.
  a[$1]=$2                    ##Creating array a with index of $1 and valus is $2.
  next                        ##next will skip all statements from here.
}
{
  key=substr($0,1,3)":"       ##Creating key which has 1st 3 characters and colon here.
}
(key in a){                   ##Checking key in array a if yes then do following.
  print $2":\t"a[key]         ##Printing 2nd field colon tab and value of a with key index here.
}
' groups.txt masters.txt      ##Mentioning Input_file names here.


2nd solution: A slight different from 1st solution.

awk '
BEGIN{
  OFS=":"
}
FNR==NR{
  a[$1]=$2
  next
}
{
  sub(/\.[0-9]+:/,OFS,$1)
  key=$1
}
(key in a){
  print $2,"\t"a[key]
}
' groups.txt masters.txt

Explanation: Adding detailed explanation for above.

awk '                           ##Starting awk program from here.
BEGIN{                          ##Starting BEGIN section of this program from here.
  OFS=":"                       ##Setting OFS as : here.
}
FNR==NR{                        ##Checking condition if FNR==NR which will be TRUE when groups.txt is being read.
  a[$1]=$2                      ##Creating array a with index $1 and value $2 here.
  next                          ##next will skip all further statements from here.
}
{
  sub(/\.[0-9]+:/,OFS,$1)       ##Substituting dot digits and colon with OFS in 1st field.
  key=$1                        ##Creating variable key which hs 1st field in it.
}
(key in a){                     ##Checking condition if key from current line is present in array a then do following.
  print $2,"\t"a[key]           ##Printing 2nd field tab and value of array a here.
}
' groups.txt masters.txt        ##Mentioning Input_file names here.

The following will work even if your input contains other :s or blanks than just the ones shown in your example:

$ cat tst.awk
BEGIN { OFS=": " }
{
    group = substr($0,match($0,/[0-9]+\.[0-9]+/),RLENGTH)
    name  = substr($0,match($0,/[^:]+: */)+RLENGTH)
}
NR==FNR {
    map[group,++cnt[group]] = name
    next
}
{
    for (i=1; i<=cnt[group]; i++) {
        print map[group,i], name
    }
}

.

$ awk -f tst.awk master.txt group.txt
name00: groupvalue0
name01: groupvalue0
name02: groupvalue0
name03: groupvalue0
name04: groupvalue0
name05: groupvalue1
name06: groupvalue1
name07: groupvalue1
name08: groupvalue1
name09: groupvalue1
name10: groupvalue2
name11: groupvalue2
name12: groupvalue2
name13: groupvalue2
name14: groupvalue2
name00: groupvalue10
name01: groupvalue10
name02: groupvalue10
name03: groupvalue10
name04: groupvalue10
name10: groupvalue12
name11: groupvalue12
name12: groupvalue12
name13: groupvalue12
name14: groupvalue12

A, slightly, different approach:

awk -F": " '{ a[$1]=$2 }
            END{ for (i in a) { x=substr(i,1,3); 
                                if (x in a && x!=i) { 
                                   print a[i] ":", a[x] }
                              }
            }' master.txt group.txt

I am just adding all info to the array (a), and then looking if there is an index with the first 3 positions.

Related