合并两列中已排序的文件

合并两列中已排序的文件

我想合并一些预先排序的制表符分隔文件:

  • 文件bygroup.0
    ancient-american    mercury 1   164
    ancient-american    mh25    2   8717664
    ancient-neolith tk11    262 40074321970
    ancientdna  jk21    6936    17069206689
    ancientdna  rm20    11267   372606702813
    ancientgen  ab34    1573    27800468142
    ancientgen  dg11    3516    45081427920
    ancientgen  fa8 7179    462396221983
    ancientgen  mp15    41  10248223517
    ancientgen  mp18    254 1049351143
    ancientgen  rm20    15100   1565340401
    ancientgen  tc9 1695    89861489631
    
  • 文件bygroup.2
    ancient-american    mercury 1   160
    ancient-american    mh25    2   10362712888
    ancient-neolith tk11    264 43842268110
    ancientdna  jk21    6919    16379509855
    ancientdna  rm20    11268   324906365415
    ancientgen  ab34    1577    33947364202
    ancientgen  dg11    3518    48092138390
    ancientgen  fa8 7174    472364587220
    ancientgen  mp15    39  32487920045
    ancientgen  mp18    254 1058177852
    ancientgen  rm20    15104   998615135
    ancientgen  tc9 1692    94858351562
    

您可以看到这 2 个文件具有相同的行数,并且基于第 1 列和第 2 列的顺序相同,并且这些列中的条目相同。

现在我想合并它们,以便按顺序输出前两列中具有相同值的所有行。

我以为sort -m这就是我所需要的,但是:

$ sort -m bygroup.*
ancient-american    mercury 1   160
ancient-american    mercury 1   164
ancient-american    mh25    2   10362712888
ancient-american    mh25    2   8717664
ancient-neolith tk11    262 40074321970
ancientdna  jk21    6936    17069206689
ancientdna  rm20    11267   372606702813
ancientgen  ab34    1573    27800468142
ancientgen  dg11    3516    45081427920
ancientgen  fa8 7179    462396221983
ancientgen  mp15    41  10248223517
ancientgen  mp18    254 1049351143
ancientgen  rm20    15100   1565340401
ancientgen  tc9 1695    89861489631
ancient-neolith tk11    264 43842268110
ancientdna  jk21    6919    16379509855
ancientdna  rm20    11268   324906365415
ancientgen  ab34    1577    33947364202
ancientgen  dg11    3518    48092138390
ancientgen  fa8 7174    472364587220
ancientgen  mp15    39  32487920045
ancientgen  mp18    254 1058177852
ancientgen  rm20    15104   998615135
ancientgen  tc9 1692    94858351562

(我添加的其他选项得到了相同的结果,例如sort -k 1,2 -ifm......)

它符合我对古代美国人的期望,但不适合其他人。发生了什么事,是否有另一种快速有效的方法来执行此操作,而无需诉诸完整排序(sort无需此处即可工作-m)。

答案1

TXR Lisp解决方案:

$ txr merge.tl 
ancient-american    mercury 1   164
ancient-american    mercury 1   160
ancient-american    mh25    2   8717664
ancient-american    mh25    2   10362712888
ancient-neolith tk11    262 40074321970
ancient-neolith tk11    264 43842268110
ancientdna  jk21    6936    17069206689
ancientdna  jk21    6919    16379509855
ancientdna  rm20    11267   372606702813
ancientdna  rm20    11268   324906365415
ancientgen  ab34    1573    27800468142
ancientgen  ab34    1577    33947364202
ancientgen  dg11    3516    45081427920
ancientgen  dg11    3518    48092138390
ancientgen  fa8 7179    462396221983
ancientgen  fa8 7174    472364587220
ancientgen  mp15    41  10248223517
ancientgen  mp15    39  32487920045
ancientgen  mp18    254 1049351143
ancientgen  mp18    254 1058177852
ancientgen  rm20    15100   1565340401
ancientgen  rm20    15104   998615135
ancientgen  tc9 1695    89861489631
ancientgen  tc9 1692    94858351562

代码:

(defstruct record ()
  key
  line
  (:method equal (me) me.key))

(defun read-recs (file)
  (build
    (awk (:set fs "\t")
         (:inputs file)
         (t (add (new record
                      key [f 0..2]
                      line rec))))))

(mapdo [chain .line put-line] (merge (read-recs "bygroup.0") (read-recs "bygroup.1")))

为了保存文件每条记录的信息,我们定义了一个record结构类型,其中包含 a key、我们的排序键和 a line,它是原始逐字行。该key槽将是两个字符串的列表。

record类型有一个equal方法,它实现平等替代。这意味着每当record通过函数equalless或比较对象时greater,都会采用该方法的值来代替该对象。例如,如果我们要访问sort一个结构列表record,而不指定比较函数,它们将根据键进行排序。

该函数read-recs借助awk.在标准 Awk 中,字段分隔符被指定为"\t" (tab). For each record, thet condition (unconditional truth) dispatches an action which creates a record object. Thekey is a sublist of thef (field) list, consisting of the first two fields. Theline is therec $0`。: the whole record.is like

build宏用于隐式的、过程性的列表构建。例如(build (add 1) (add 2))将返回列表(1 2)build创建一个作用域,在该作用域中调用将添加到隐式隐藏列表,该列表在终止add时返回。build

通过相等替换,获得了正确键入所需键的read-recs类型record,我们所要做的就是读取这两个文件,然后将它们交给函数merge以获取排序列表。

record然后,通过两个函数的链接来映射此列表中的对象::[chain .line put-line].line函数检索line对象的槽,然后将put-line其转储到标准输出,后跟换行符。


read-recs不使用buildand的函数的替代实现awk可能是:

(defun read-recs (file)
  (collect-each ((line (file-get-lines file)))
    (let ((fields (spl #\tab line)))
      (new record key [fields 0..2]
                  line line))))

答案2

使用 R 编程语言

保存文本文件,并将一个或多个空格字符替换为单个制表符。将两个数据文件读入R:

> group0 <- read.delim("/Users/admin/bygroup.0", header=FALSE)
> group2 <- read.delim("/Users/admin/bygroup.2", header=FALSE)
> head(group0)
                V1      V2    V3           V4
1 ancient-american mercury     1          164
2 ancient-american    mh25     2      8717664
3  ancient-neolith    tk11   262  40074321970
4       ancientdna    jk21  6936  17069206689
5       ancientdna    rm20 11267 372606702813
6       ancientgen    ab34  1573  27800468142
> head(group2)
                V1      V2    V3           V4
1 ancient-american mercury     1          160
2 ancient-american    mh25     2  10362712888
3  ancient-neolith    tk11   264  43842268110
4       ancientdna    jk21  6919  16379509855
5       ancientdna    rm20 11268 324906365415
6       ancientgen    ab34  1577  33947364202

要合并数据文件,请使用 R 的merge()函数:

> merge(group0, group2, by = c("V1","V2"))
                 V1      V2  V3.x         V4.x  V3.y         V4.y
1  ancient-american mercury     1          164     1          160
2  ancient-american    mh25     2      8717664     2  10362712888
3   ancient-neolith    tk11   262  40074321970   264  43842268110
4        ancientdna    jk21  6936  17069206689  6919  16379509855
5        ancientdna    rm20 11267 372606702813 11268 324906365415
6        ancientgen    ab34  1573  27800468142  1577  33947364202
7        ancientgen    dg11  3516  45081427920  3518  48092138390
8        ancientgen     fa8  7179 462396221983  7174 472364587220
9        ancientgen    mp15    41  10248223517    39  32487920045
10       ancientgen    mp18   254   1049351143   254   1058177852
11       ancientgen    rm20 15100   1565340401 15104    998615135
12       ancientgen     tc9  1695  89861489631  1692  94858351562

write.delim()可以使用或函数将数据再次写回write.csv()。要获得帮助,请在提示符下键入命令,前面加问号,如?getwd()?setwd()或。?read.delim()?merge()

[注意:根据 R 安装的年龄,您可能必须stringsAsFactors=FALSE在每个read.delim()函数调用中包含该参数]。

https://www.r-project.org/
https://cran.r-project.org/index.html

相关内容