我想合并一些预先排序的制表符分隔文件:
- 文件
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
通过函数equal
、less
或比较对象时greater
,都会采用该方法的值来代替该对象。例如,如果我们要访问sort
一个结构列表record
,而不指定比较函数,它们将根据键进行排序。
该函数read-recs
借助awk
.在标准 Awk 中,字段分隔符被指定为"\t" (tab). For each record, the
t condition (unconditional truth) dispatches an action which creates a record object. The
key is a sublist of the
f (field) list, consisting of the first two fields. The
line is the
rec $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
不使用build
and的函数的替代实现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