如何根据原始文件的第一列值组织新文件?

Posted

技术标签:

【中文标题】如何根据原始文件的第一列值组织新文件?【英文标题】:How do I organize new files according to the first column values of the original files? 【发布时间】:2016-02-12 22:50:24 【问题描述】:

假设我有 3 个文件:File-AFile-BFile-C;其中每个文件有两列数据(空间划定),但行数未知(和可变)。

输入

File-A:
1 dE
1 dF         
2 dF
2 dH         

File-B:    
1 dI         
3 dJ
3 dK         

File-C:
2 dF
3 dH
3 dJ
3 dK
4 dL

如何有效地对数据进行排序,以便为第一列中的每个值创建新文件(即File-1File-2File-3File-4),以跟踪他们的第二列合作伙伴数据和原始文件名?

期望的输出

File-1:      
A dE
A dF
B dI

File-2:    
A dF
A dH         
C dF         

File-3:
B dJ
B dK
C dH
C dJ
C dK

File4:
C dL

实际上,我有几十万个原始文件,每个文件都有几百行数据(但原始文件和新文件的总数是已知的)。实现这种排序最省时的方法是什么?

与 Fortran 之类的程序相比,Bash 脚本会是最快的方法吗?我只是在学习 sed 和 awk——这样的东西效果最好吗?

如果在链接之前提出了类似的问题,我们将不胜感激。到目前为止,我发现的 closest question 似乎表明 awk 可能是一种方法。

【问题讨论】:

“与 [...] 相比,bash 脚本会是最快的方法吗?”:否 :) 【参考方案1】:

这是一个(可能非常慢)Bash 解决方案:

#!/bin/bash

for suffix in "$@##*-"; do    # Get suffix from each file name
    while read -r col1 col2; do # Read two columns

        # Assemble output line and write to proper file
        printf "%s %s\n" "$suffix" "$col2" >> "File-$col1"
    done < "File-$suffix"
done

Bash 循环很慢,许多重定向很慢,但我想不出另一种方法,因为每个输入行都可能转到另一个输出文件。

在 awk 中可能会更快:

#!/usr/bin/awk -f

# For each new file, get the file name suffix
FNR == 1 
    split(FILENAME, arr, "-")
    suffix = arr[2]


# On each line, create the output file name, then print to that file

    ofname = "File-" $1
    print suffix, $2  > ofname

两者都使用./scriptname File-*从命令行调用。

限制打开文件句柄的数量

可以同时打开多少个文件句柄是有限制的:从您的操作系统和从 awk。 Gawk 做了一些诡计1 来解决这个问题,但它可能仍然更快(并且肯定更便携)以避免打开文件句柄过多。

例如,一种补救措施是跟踪每个输入文件的打开文件句柄,然后在处理下一个文件之前关闭它们:

#!/usr/bin/awk -f

# For each new file, get the file name suffix
FNR == 1 
    # Close open files
    for (fname in openfiles)
        close(openfiles[fname])
    split(FILENAME, arr, "-")
    suffix = arr[2]


# On each line, create the output file name, then print to that file

    ofname = "File-" $1
    openfiles[ofname] = 1   # Keep track of open files
    print suffix, $2  > ofname


1来自manual:

如果您使用的文件多于系统允许您打开的文件,gawk 会尝试在您的数据文件中多路复用可用的打开文件。 gawk 执行此操作的能力取决于您的操作系统的功能,因此它可能并不总是有效。

因此,当您使用完文件后,始终在文件上使用close() 既是良好做法,也是良好的可移植性建议。事实上,如果您使用大量管道,则在完成后关闭命令是必不可少的。

【讨论】:

awk 脚本是正确的方法,并且将比 shell 循环快几个数量级,但您应该提到,如果它不是 gawk,那么它需要在运行时关闭()文件或最终同时打开太多。

以上是关于如何根据原始文件的第一列值组织新文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据 Python、R 中不同数据框/患者之间的第一列元素/基因取第二列值/计数的平均值?

如何从 CSV 文件中获取每一行的第一列?

根据 JTable 中的第一列值着色特定行?

如何在for和if循环中获取spark scala数据帧的最后一行的第一列值

识别 pyspark 中第一次出现的列值,然后根据它增加另一列

jQuery:获取 HTML 表格第四行(仅)的第一列值