对文本文件中的列进行排序并删除python中不需要的行

时间:2017-03-20 11:27:05

标签: python list file

我有一个包含四列的文本文件:

time serial domain server

该文件的内容如下:

15 14 google.com 8.8.8.8
19 45 google.com 8.8.4.4
98 76 google.com 208.67.222.222
20 23 intuit.com 8.8.8.8
45 89 intuit.com 8.8.4.4
43 21 intuit.com 208.67.222.222
78 14 google.com 8.8.8.8
92 76 google.com 8.8.4.4
64 54 google.com 208.67.222.222
91 18 intuit.com 8.8.8.8
93 74 intuit.com 8.8.4.4
65 59 intuit.com 208.67.222.222

我最终想要的是具有最高序列号的域和服务器组合,如下所示:

15 14 google.com 8.8.8.8
92 76 google.com 8.8.4.4
98 76 google.com 208.67.222.222
20 23 intuit.com 8.8.8.8
45 89 intuit.com 8.8.4.4
65 59 intuit.com 208.67.222.222

此外,如果序列号匹配,例如google.com的8.8.8.8,请选择时间最短的行。

实现这一目标的最佳方法是什么?逐行读取每一行或执行readlines()将所有内容转储到列表中然后继续进行?我目前的代码非常混乱,正在寻找其他更简洁的方法来实现它

3 个答案:

答案 0 :(得分:4)

如果你想在这个问题上抛出一个外部库,pandas会非常容易:

data = pd.read_csv('/tmp/test.data', sep=' ', header=None)
new = data.sort_values(1, ascending=False).groupby([2, 3], as_index=False).first().reindex_axis(sorted(data.columns), axis=1)

这将导致:

    0   1           2               3
0  98  76  google.com  208.67.222.222
1  92  76  google.com         8.8.4.4
2  15  14  google.com         8.8.8.8
3  65  59  intuit.com  208.67.222.222
4  45  89  intuit.com         8.8.4.4
5  20  23  intuit.com         8.8.8.8

您可以使用以下方法将其保存到文件中:

new.to_csv('/tmp/new.dat', sep=' ', header=False, index=False)

答案 1 :(得分:1)

在对数据进行适当排序后,您可以使用itertools.groupby执行此操作。

from itertools import groupby

''' Find domain and server combination with the highest serial number 
    if serial numbers match, select the row with the least time.
'''

print('time serial domain server')

src = '''\
15 14 google.com 8.8.8.8
19 45 google.com 8.8.4.4
98 76 google.com 208.67.222.222
20 23 intuit.com 8.8.8.8
45 89 intuit.com 8.8.4.4
43 21 intuit.com 208.67.222.222
78 14 google.com 8.8.8.8
92 76 google.com 8.8.4.4
64 54 google.com 208.67.222.222
91 18 intuit.com 8.8.8.8
93 74 intuit.com 8.8.4.4
65 59 intuit.com 208.67.222.222
'''

# Read data into a list of tuples, converting time & serial to int
data = [row.split() for row in src.splitlines()]
data = [(int(row[0]), int(row[1]), row[2], row[3]) for row in data]

# Sort and group
data.sort(key=lambda t: (t[2], t[3], -t[1], t[0]))
for k, g in groupby(data, key=lambda t: (t[2], t[3])):
    print(list(g)[0])

<强>输出

(98, 76, 'google.com', '208.67.222.222')
(92, 76, 'google.com', '8.8.4.4')
(15, 14, 'google.com', '8.8.8.8')
(65, 59, 'intuit.com', '208.67.222.222')
(45, 89, 'intuit.com', '8.8.4.4')
(20, 23, 'intuit.com', '8.8.8.8')

将数据读入元组列表后,将时间和时间放在一起。串行值转换为整数,我们排序(域,服务器, - 序列,时间)。负号表示序列排序从最高到最低完成。

然后我们按(域,服务器)分组,并获取具有相同域和项的每组项目中的第一项。服务器。这将使我们获得具有最高序列号的项目,如果组中有多个具有该序列号的项目,则具有最低时间的项目将是第一个。

groupby键功能也可以写成

lambda t: t[2:]

使用正确的def函数代替lambda s可以使代码更具可读性。

def sort_key(t):
    time, serial, domain, server = t
    return domain, server, -serial, time

def groupby_key(t):
    time, serial, domain, server = t
    return domain, server

# Sort and group
data.sort(key=sort_key)
for k, g in groupby(data, key=groupby_key):
    print(list(g)[0])

相反,我们可以通过将其缩小为一个难以理解的嵌套列表理解/生成器表达式来使 less 可读。 :)

from itertools import groupby

src = '''\
15 14 google.com 8.8.8.8
19 45 google.com 8.8.4.4
98 76 google.com 208.67.222.222
20 23 intuit.com 8.8.8.8
45 89 intuit.com 8.8.4.4
43 21 intuit.com 208.67.222.222
78 14 google.com 8.8.8.8
92 76 google.com 8.8.4.4
64 54 google.com 208.67.222.222
91 18 intuit.com 8.8.8.8
93 74 intuit.com 8.8.4.4
65 59 intuit.com 208.67.222.222
'''

newdata = [list(g)[0] for k, g in groupby(
    sorted(((int(row[0]), int(row[1]), row[2], row[3]) 
    for row in (row.split() for row in src.splitlines())),
    key=lambda t: (t[2], t[3], -t[1], t[0])), key=lambda t: t[2:])]

for row in newdata:
    print(row)

答案 2 :(得分:0)

这是一个没有外部库的解决方案:

(defrecord Stoptest [&args])
(def test (Stoptest. [:c101 :main-office :a1]))

; gets the values out 
(doseq [arg (:&args test)] (print arg))