0

I have a text file with the following contents:

ABC 1
XYZ 1
QWE 1
GRE 1
DGD 2
GER 2
OUT 2
RTY 3
POI 3
MNB 3
LKJ 3

Expected output:

ABC XYZ QWE GRE
DGD GER OUT 
RTY POI MNB LKJ 

ie., All words with the same second column value should appear in a same line separated by a single space.

1

5 Answers 5

2

Using any awk and printing the output records in the same order as they appear in the input and without reading all of the input into memory:

$ awk '
    $2 != prev { if (NR>1) print rec; rec=$1; prev=$2; next }
    { rec = rec OFS $1 }
    END { print rec }
' file
ABC XYZ QWE GRE
DGD GER OUT
RTY POI MNB LKJ

The above assumes your input is grouped by your 2nd field values as shown in your sample input, if that's not the case then just sort them first - sort -k2,2 file | awk 'script'

The above just stores the set of $1s for a $2 in memory as each $2 appears in the input, if you don't even want to do that you could just print the $1s as they appear:

$ awk '
    $2 != prev { if (NR>1) print ""; printf "%s", $1; prev=$2; next }
    { printf "%s%s", OFS, $1 }
    END { print "" }
' file
ABC XYZ QWE GRE
DGD GER OUT
RTY POI MNB LKJ
1

Something like can do the work:

awk '{a[$2]=a[$2]" "$1} END {for (i in a) print substr(a[i],2)}'

The substr is used to remove leading space

4
  • 1
    Wouldn't the use of OFS be useful in more case ? And is it more efficient to use a substr at the end or would it be better to use a conditional when adding element to the array ? Commented Dec 19, 2022 at 8:06
  • 1
    @Marius_Couet, OFS IMHO is not applicable here because we concatenate strings, not print the tokens. substr at the end execute only number of times of resulting rows. If use if it will execute on every row from source file. And if you have (for example) millions of rows in source will slow down the execution. Commented Dec 19, 2022 at 8:14
  • 2
    Thanks for the explanation for the substr part. But about the OFS part you can concatenate it. a[$2]=a[$2]" "$1 can be replaced by a[$2]=a[$2] OFS $1, but in that case you'd need to replace the substr number with length(OFS)+1 (for it to be applicable in any cases) Commented Dec 19, 2022 at 8:23
  • 1
    @Marius_Couet, yes, this can work. Also instead of OFS you can use any predefined variable in awk. But I personally prefer to have clear and sample code :) Commented Dec 19, 2022 at 9:04
1

Using Miller (mlr) to process the header-less "pretty-printed" (whitespace-delimited) data:

$ mlr --pprint -N nest --ivar ' ' -f 1 then cut -f 1 file
ABC XYZ QWE GRE
DGD GER OUT
RTY POI MNB LKJ

This folds the entries from the first field using Miller's nest operation, grouped by the data in the second field. The folded entries will be delimited by spaces (the character in single quotes on the command line). The second operation, cut, extracts only the folded field.

0

Using awk (actually gawk in my case):

 awk '{array[$2]=($2 in array ? array[$2]" " : "") $1} END{for (key in array) print array[key]}' data.txt

Or if you want to remove the ternary operator (condition ? value : value):

awk '{array[$2]=array[$2]" "$1} END{for (key in array) print array[key]}' data.txt

The difference between both awk commands is that the second one will print a space at the beginning of each line:

#First awk command:
ABC XYZ QWE GRE
DGD GER OUT
RTY POI MNB LKJ

#Second one:
 ABC XYZ QWE GRE
 DGD GER OUT
 RTY POI MNB LKJ
0
0

Using datamash:

$ datamash -sW groupby 2 collapse 1 --collapse-delimiter ' ' <file | datamash cut 2

About collapse delimiter from its manual:

--collapse-delimiter=x
-c x
Use character X instead of comma to delimit items in a ‘collapse’ or ‘unique’ (aka ‘uniq’) list.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .