基于两列提取行数据

时间:2014-10-16 00:48:55

标签: python database bash awk

我想在序言中说我非常喜欢初学者。

我有两个txt文件。在两列(i,j)中具有约1000个值的一个,指的是已经破碎的成对颗粒。第二个文件包含所有4M粒子列中的XYZ坐标,其中粒子标记(i或j)是行号。我需要从文件1中取出标签(i和j)并找到它们关联的XYZ坐标,以便我得到一个具有以下格式的新文件:

输出: Xi Yi Zi Xj Yj Zj

每个破碎的粒子对。

我不确定使用它的最佳工具是什么。我有一些awk和bash以及python的经验,但我没有到达任何地方。

文件1:

C6i C7j
2084974 2135208
380134 632561
416969 416972
86296 86300
2296040 2343415
493401 562376
444984 522708
405188 536773
84709 130065

文件2:XYZ分别是第3,4和5列。

ni    -0.139703912516E-01 -0.588106472470E-02 -0.246993537185E-01  0.240235100000E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
al    -0.137235866800E-01 -0.641882704213E-02 -0.251673100913E-01  0.534478800000E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
ni    -0.185856021576E-01 -0.152366221623E-01 -0.121702424186E-01  0.243473343750E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
ni    -0.189394000761E-01 -0.152668306704E-01 -0.124951222187E-01  0.247782468750E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
ni    -0.186657676593E-01 -0.149796823498E-01 -0.117824363740E-01  0.245485618750E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
ni    -0.183548072309E-01 -0.146581691495E-01 -0.119760428210E-01  0.262177487500E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
al    -0.179781075366E-01 -0.152651341795E-01 -0.118226752981E-01  0.476129550000E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
al    -0.184341198964E-01 -0.147587453602E-01 -0.127106194529E-01  0.509758600000E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
ni    -0.162533369485E-01 -0.349146188426E-01 -0.141615273706E-01  0.253299731250E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
ni    -0.163557464187E-01 -0.344963153936E-01 -0.143620570810E-01  0.239937831250E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
ni    -0.166373601765E-01 -0.351914412333E-01 -0.135853527002E-01  0.244891000000E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
al    -0.158054048322E-01 -0.352289094572E-01 -0.137329142337E-01  0.462249725000E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
ni    -0.405319274446E-01 -0.296567975721E-01 -0.243386549644E-01  0.254679675000E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00
ni    -0.409494727711E-01 -0.296234747969E-01 -0.240603258346E-01  0.250886643750E-03  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00  0.0000E+00

3 个答案:

答案 0 :(得分:2)

使用awk

awk 'FNR==NR {xyz[FNR]=$3" "$4" "$5;next;} {print xyz[$1],xyz[$2];}' file2 file

假设file1为:

C6i C7j
2   3
6   1

file2与您的问题相同,然后:

$ awk 'FNR==NR {xyz[FNR]=$3" "$4" "$5;next;} {print xyz[$1],xyz[$2];}' file2 file1

-0.641882704213E-02 -0.251673100913E-01 0.534478800000E-03 -0.152366221623E-01 -0.121702424186E-01 0.243473343750E-03
-0.146581691495E-01 -0.119760428210E-01 0.262177487500E-03 -0.588106472470E-02 -0.246993537185E-01 0.240235100000E-03

工作原理:

awk命令按此顺序给出了两个文件:file2 file1awk隐式循环遍历文件的每一行。

  • FNR==NR {xyz[FNR]=$3" "$4" "$5;next;}

    FNR是到目前为止从当前文件读取的行数,NR是到目前为止从所有文件读取的行总数。因此,当FNR==NR时,这意味着我们正在读取命令行中列出的第一个文件。对于该文件,我们将列3,4,5保存到由其行号索引的数组xyz中。

    next命令告诉awk跳过剩余的命令并跳转到下一行重新开始。

  • print xyz[$1],xyz[$2]

    如果我们到达此处,我们正在处理第二个命名文件file1。我们查找数组xyz中此行上命名的两个粒子的坐标并将其打印出来。

答案 1 :(得分:1)

您可以使用product中的itertools以及一些列表操作

from itertools import product

raw_data1 = open('data1.txt').read()
"""
data1.txt holds:
1 2
2 3
"""

raw_data2 = """
a b c d
e f g h
i j k l
"""

data1 = [map(int, x.split()) for x in filter(None, raw_data1.splitlines())]
data2 = [x.split() for x in filter(None, raw_data2.splitlines())]

take_coloumns = lambda x: (x[1], x[2], x[3])

for x, y in data1:
    print [take_coloumns(list(product([x], data2[x-1]))),
           take_coloumns(list(product([y], data2[y-1])))]

data2[y-1]是因为python是零索引的,我想你的行是1索引的。代码将输出:

[((1, 'b'), (1, 'c'), (1, 'd')), ((2, 'f'), (2, 'g'), (2, 'h'))]
[((2, 'f'), (2, 'g'), (2, 'h')), ((3, 'j'), (3, 'k'), (3, 'l'))]

你看到了这个想法?如果你有大量的数据,你应该使用动态编程来记住线性的核心化。

答案 2 :(得分:0)

这是bash的尝试,而不是我害怕的最佳解决方案, Python C (甚至 awk ??)应该更适合这份工作

描述:
input file1,col 6 is col 7是j?
输入file2,我们需要col 3,4,5?
因为file2中有400万行,所以无法以方便的方式在bash中使用数组。

这会很慢,所以如果你将file2复制到RAM(无论是作为tmpfs安装的是什么)都是最好的

#!/bin/bash

while read c1 c2 c3 c4 c5 i j
do
    sed -n "^$i""p" file2| { read c1 c2 X Y Z ; echo -n "$X $Y $Z ";}
    sed -n "^$j""p" file2| { read c1 c2 X Y Z ; echo    "$X $Y $Z" ;}
done <file1 >output_file