以下のファイルがあります。
47196436 47723284 name1 1.77273
42672249 52856963 name2 1.06061
52856963 430695 name2 1.16667
55094959 380983 name3 1.55613
17926380 55584836 name4 1.02461
3213456 34211 name4 1.11
54321 34211 name4 1.23
最初の2つの列は私のテーブルの主キーに対応しています。同じ名前がある場合は、すべてのキーが同じ行になるように行をマージしようとします。
出力を取得しようとしています。
47196436 47723284 name1
42672249 52856963 430695 name2
55094959 380983 name3
17926380 55584836 3213456 34211 54321 name4
次のコマンドを使用して部分的に達成できました。
awk '{ x[$3]=x[$3] " " $2; }
END {
for (k in x) print k,x[k] >"OUTPUT1";
}' ccc.txt
しかし、それは私に正しい出力を提供しません。上記のコマンドをさらに修正するには、助けが必要です。
答え1
不器用だが仕事を果たしたようだ
awk '$3 != prev {if (NR != 1) print prev; prev=$3; delete a};
!($1 in a){a[$1]++; printf "%s ", $1};
!($2 in a){a[$2]++; printf "%s ", $2};
END {print prev}' ccc.txt
47196436 47723284 name1
42672249 52856963 430695 name2
55094959 380983 name3
17926380 55584836 3213456 34211 54321 name4
答え2
一方perl
通行:
$ perl -ane '$h{$F[2]} .= " ".$F[0]." ".$F[1];
END {
for $k (sort keys %h) {
print $_," " for grep {!$seen{$_}++} split(" ",$h{$k});
print "$k\n";
}
}' file
47196436 47723284 name1
42672249 52856963 430695 name2
55094959 380983 name3
17926380 55584836 3213456 34211 54321 name4
答え3
Perlのもう一つのアプローチは次のとおりです。
$ perl -ane 'foreach(@F[0..1]){$k{$F[2]}{$_}++}
END{
foreach $v (sort keys(%k)){
print "$_ " foreach(keys(%{$k{$v}}));
print "$v\n"
};
} ' file
これで以下が生成されます。
47723284 47196436 name1
42672249 430695 52856963 name2
380983 55094959 name3
34211 55584836 17926380 54321 3213456 name4
説明する
いいですね。上記のPerlスクリプトは、Perlの理解しやすい例ではないことを認めています。私は多くのトリックを使用し、彼らはコードを難読化しました。ここでは同じ解決策を提案しますが、スクリプト形式でより冗長なアプローチを使用します。
#!/usr/bin/perl
## This is the hash that will store our values.
my %k;
## Read through the input file line by line
## saving each line as $line. This is what the -n
## switch to perl means, only there each line is saved
## in the special variable $_.
while (my $line=<>) {
## Split the line into the @F array. This is
## what the -a switch does.
#chomp($line);
my @F=split(/\s+/,$line);
## Populate the %k hash that we defined at the beginning.
## This is a hash of hashes, it looks like this:
## $hash{key1}{key2}=value
## In this case, we are saying:
## $hash{3rd field}{1st field}=1
## $hash{3rd field}{2nd field}=1
## This just serves to add the 1st and 2nd fields
## to the list of fields for this $F[2] (the 3rd field, the name).
## A side effect of this is that hash keys are unique so duplicates
## are automatically removed.
$k{$F[2]}{$F[0]}=1;
$k{$F[2]}{$F[1]}=1;
}
## We have now finished processing the file
## (this is the END{} block above), so let's print.
## This saves the keys of the hash %k in the @names array
## sorted alphabetically.
my @names=(sort keys(%k));
## Go through each of the names, saving
## them as $name
foreach my $name (@names) {
## Now, iterate through the values associated
## with the current $name. These are saved as the
## keys of the hash %k{$name}
foreach my $value ( (keys(%{$k{$name}})) ){
print "$value ";
}
## Now print the name as well
print "$name\n";
}
上記のスクリプトは、私が投稿したスクリプトとまったく同じことを行い、よりきれいな構文を使用するように拡張されました。
答え4
を使用しても問題ない場合は、gawk >= 4.0
以下を使用してください(特別な) はオプションの名前とキーの順序を使用して、目的の出力を生成します。
NF {
Names[$3][$1] = 1;
Names[$3][$2] = 1;
}
END {
PROCINFO["sorted_in"] = "@ind_str_asc"; # if you want `Name` ordered
for (Name in Names) {
PROCINFO["sorted_in"] = "@ind_num_asc"; # if you want `Key` ordered
for (Key in Names[Name]) {
printf("%s ", Key);
}
print Name;
}
}
以下を提供します。
47196436 47723284 name1
430695 42672249 52856963 name2
380983 55094959 name3
34211 54321 3213456 17926380 55584836 name4