给定以下两个按第 1 列和第 2 列排序的文件:
f1:
card1,value1,f1c11,f1c12
card2,value2,f1c21,f1c22
card3,value3,f1c31,f1c32
card4,value4,f1c41,f1c42
card4,value4,f1c411,f1c412
card4,value41,f1c421,f1c422
card5,vaule5,f1c51,f1c52
f2:
card,value2,f2c1,f2c2
card2,value,f2c21,f2c22
card2,value2,f2c211,f2c212
card2,value2,f2c221,f2c222
card3,value3,f2c31,f2c32
card4,value4,f2c41,f2c42
card4,value4,f2c411,f2c412
card5,vaule5,f2c51,f2c52
card6,vaule6,f2c61,f2c62
card7,vaule5,f2c71,f2c72
期望:将 f1 连接到 f2,以便每个可连接的 f1 记录仅与 f2 中第一个可用的可匹配记录连接一次:
card2,value2,f1c21,f1c22,f2c211,f2c212
card3,value3,f1c31,f1c32,f2c31,f2c32
card4,value4,f1c41,f1c42,f2c41,f2c42
card4,value4,f1c411,f1c412,f2c41,f2c42
card5,vaule5,f1c51,f1c52,f2c51,f2c52
详细匹配逻辑如下:
- f1(第 1 行)中的 card1,value1 在 f2 中看不到任何匹配项 -> 忽略
- f1(第 2 行)中的 card2,value2 在 f2(第 3 行)中看到第一个匹配项,在此匹配之后,f1 第 2 行和 f2 第 3 行不再可用 -> card2,value2,f1c21,f1c22,f2c211,f2c212
- f1(第 3 行)中的 card3,value3 在 f2(第 5 行)中看到第一个匹配项,在此匹配之后,f1 第 3 行和 f2 第 5 行不再可用 -> card3,value3,f1c31,f1c32,f2c31,f2c32
- f1(第 4 行)中的 card4,value4 在 f2(第 6 行)中看到第一个匹配项,在此匹配之后,f1 第 4 行和 f2 第 6 行不再可用 -> card4,value4,f1c41,f1c42,f2c41,f2c42
- f1(第 5 行)中的 card4,value4 在 f2(第 7 行)中看到第一个匹配项,在此匹配之后,f1 第 5 行和 f2 第 7 行不再可用 -> card4,value4,f1c411,f1c412,f2c41,f2c42
- f1 中的 card4,value4(第 6 行)在 f2 中没有看到任何匹配项 -> 忽略
- f1(第 7 行)中的 card5,value5 在 f2(第 8 行)中看到第一个匹配项,在此匹配之后,f1 第 7 行和 f2 第 8 行不再可用 -> card5,vaule5,f1c51,f1c52,f2c51,f2c52
答案1
用 Bash 和 GNU awk 编写脚本。这不需要对任一输入文件进行排序:输出按照作为参数传递的第一个文件的顺序排列。
我认为您的第四条输出行有错误:它再次重复 f2 card4 第一行。
第二个文件的整个内容保存在一个数组 Row 中,行号按输入顺序以列表形式保存在 Map 中。
然后,第一个文件删除它使用的任何映射条目,直到没有剩余。
#! /bin/bash --
#:: firstJoin: join only the first records with matching keys.
Join () {
local AWK='
BEGIN { FS = ","; OFS = ","; reClip = "^[^,]*,[^,]*,"; }
#.. Store input from first file.
function Store (key, tx, Local) {
sub (reClip, "", tx);
Row[FNR] = tx;
Map[key] = Map[key] FNR FS FS;
}
#.. Pair second file with first available.
function Pair (key, tx, Local) {
if (! (key in Map) || (Map[key] == "")) return;
printf ("%s%s%s\n", tx, OFS, Row[0+Map[key]]);
sub (reClip, "", Map[key]);
}
FNR == NR { Store( $1 FS $2, $0); next; }
{ Pair( $1 FS $2, $0); }
'
awk -f <( printf '%s' "${AWK}" ) "${2}" "${1}"
}
Join "${1}" "${2}"
测试拍摄:
Paul--) ./firstJoin JoinF1 JoinF2
card2,value2,f1c21,f1c22,f2c211,f2c212
card3,value3,f1c31,f1c32,f2c31,f2c32
card4,value4,f1c41,f1c42,f2c41,f2c42
card4,value4,f1c411,f1c412,f2c411,f2c412
card5,vaule5,f1c51,f1c52,f2c51,f2c52
Paul--)