将 f1 连接到 f2,以便每个可连接的 f1 记录仅与 f2 中第一个可用的可匹配记录连接一次

将 f1 连接到 f2,以便每个可连接的 f1 记录仅与 f2 中第一个可用的可匹配记录连接一次

给定以下两个按第 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--) 

相关内容