文档内容如下:
(数据对) (信息)
----------------- ------------------------
1 2 3 4 5
----------------- ------------------------
pr333 sd23a2 thisisa 1001 1005
pr333 sd23a2 sentence 1001 1005
pr33w sd11aa we 1022 1002
pr33w sd11aa have 1022 1002
pr33w sd11aa adream 1033 1002
......
第 1, 2 列作为一个 数据对
如果前两列相同,判断后面的是否相同,如果不同就连接起来,合并成一行
如同下面的效果:
pr333 sd23a2 thisisa|sentence 1001 1005
pr33w sd11aa we|have|adream 1022|1033 1002
....
小白,不懂怎么做,只能想到用字典,好像又行不通,求各位大神帮忙
阿神2017-04-17 17:52:17
如果要保持输出的顺序的话就要用上OrderedDict
了,key用OrderedDict
来保持顺序,后面的信息用list
来保持顺序,后面可以乱的话,用set
是更好的选择
import re
from collections import OrderedDict
datas = OrderedDict()
with open('info.txt') as f:
for line in f:
if not line.strip().startswith('pr'):
continue
items = re.split(r'\s+', line.strip())
key = ' '.join(items[:2])
if key not in datas:
datas[key] = [[item] for item in items[2:]]
else:
for item, data in zip(items[2:], datas[key]):
data.append(item)
for key, value in datas.items():
print(key, *map('|'.join, value))
阿神2017-04-17 17:52:17
说明一下这个代码所有的考量.
首先是 顺序,这里的顺序有两个部分,一个是输出行的顺序,一个是项目合并之后的顺序.我们观察到:
pr333 sd23a2 thisisa 1001 1005
pr333 sd23a2 sentence 1001 1005
pr33w sd11aa we 1022 1002
pr33w sd11aa have 1022 1002
pr33w sd11aa adream 1033 1002
要变成:
pr333 sd23a2 thisisa|sentence 1001 1005
pr33w sd11aa we|have|adream 1022|1033 1002
输出行的顺序要顾及: pr333 先于 pr33w
项目合并之后的顺序要顾及: thisisa 先于 sentence
这代表我们 使用的资料型态必须要能维持顺序
其次是速度,我们都知道序列型态是线性搜寻,为了效率,使用映射型态是比较好的.
三种考量之下,就如同 moling3650 大所言,OrderedDict
是个好选择.这可以解决行输出的问题,不过合并项目由于只需要用到key 而不需要用到value 所以使用OrderedDict
有点可惜,不过目前标准库中没有OrderSet
的选择,所以只好将就着用一下. OrderedDict
是個好選擇.這可以解決行輸出的問題,不過合併項目由於只需要用到 key 而不需要用到 value 所以使用 OrderedDict
有點可惜,不過目前標準庫中沒有 OrderSet
的選擇,所以只好將就著用一下.
有關於 OrderedDict 可以參閱 OrderedDict
其實有一個 OrderedSet 的第三方庫 OrderedSet
或者可以自己實作,請參考 OrderedSet (Python recipe)
最後 linkse7en 大的觀點非常好,這類文檔處理的問題,如果能夠邊讀邊寫,邊讀邊處理絕對是 有效率(因為只需要進行一次文檔的走訪)(討論請見評論部分 moling 大的觀點
) 且 省資源(馬上輸出完畢,不必浪費空間儲存資料).但因為考慮到有可能重複的 數據對 有可能跨行出現,所以依然是多花一點資源來確保穩固性.
代碼(Python3):
from collections import OrderedDict
data = OrderedDict()
DPAIR = slice(0,2)
MSG = slice(2,None)
with open('data.txt', 'r') as reader:
for line in reader:
line = line.strip()
items = tuple(line.split())
msgs = data.setdefault(items[DPAIR], [OrderedDict({}) for msg in items[MSG]])
for idx, msg in enumerate(msgs):
msg.setdefault(items[MSG][idx], None)
for (dp1, dp2), msgs in data.items():
print(dp1, dp2, *['|'.join(msg.keys()) for msg in msgs])
關於代碼部分也做個說明(也許我寫的不是最好,但有些心得可以分享).
首先是 slice
類的應用.
身為一個 Python programmer,我們對 序列型態 取切片(slicing) 應該都不陌生.
items[start:stop:step]
其實可以寫成:
items[slice(start, stop, step)]
# example
items[:5] 可以寫成 items[slice(0,5)]
items[7:] 可以寫成 items[slice(7,None)]
那好處是什麼呢?
我們可以利用這個特性對切片進行命名,以這個問題的代碼為例,原本要取出 數據對 與 其他資料 可以用:
items = tuple(line.split())
items[0:2] # 這是用來做 key 的數據對
items[2:] # 這是其他的資料項
但是這種方式其實閱讀起來不夠清晰,我們可以幫這兩個範圍取個名字,所以:
DPAIR = slice(0,2)
MSG = slice(2,None)
items[DPAIR] # 這是用來做 key 的數據對
items[MSG] # 這是其他的資料項
我們可以用比較優雅易讀的方式來從 items
中取值.
其次是 setdefault
,這個函數相當實用,舉例:
dic.setdefault(key, default_value)
如果字典(或其他相符的映射型態)中存在鍵值 key
則回傳 dic[key]
否則回傳自動在字典中插入新的鍵值對 dic[key] = default_value
並且回傳 default_value
有关于 OrderedDict 可以参阅 OrderedDict
🎜其实有一个 OrderedSet 的第三方库 OrderedSet
讨论请见评论部分moling 大的观点
) 且🎜省资源🎜(马上输出完毕,不必浪费空间储存资料).但因为考虑到有可能重复的 数据对 有可能🎜跨行🎜出现,所以依然是多花一点资源来确保稳固性. 🎜
🎜
🎜🎜代码(Python3)🎜:🎜
for (a, b), c, d in ((1,2) ,3, 4):
print(a, b, c, d) # 印出 1 2 3 4
🎜
🎜关于代码部分也做个说明(也许我写的不是最好,但有些心得可以分享). 🎜
🎜首先是 slice
类的应用. 🎜
🎜身为一个 Python programmer,我们对 🎜序列型态🎜 取切片(slicing) 应该都不陌生. 🎜
rrreee
🎜其实可以写成:🎜
rrreee
🎜那好处是什么呢?🎜
🎜我们可以利用这个特性对切片进行命名,以这个问题的代码为例,原本要取出 🎜数据对🎜 与 🎜其他资料🎜 可以用:🎜
rrreee
🎜但是这种方式其实阅读起来不够清晰,我们可以帮这两个范围取个名字,所以:🎜
rrreee
🎜我们可以用比较优雅易读的方式来从 items
中取值. 🎜
🎜
🎜其次是 setdefault
,这个函数相当实用,举例:🎜
rrreee
🎜如果字典(或其他相符的映射型态)中存在键值key
则回传dic[key]
否则回传自动在字典中插入新的键值对dic[key] = default_value
并且回传default_value
. 🎜
🎜
🎜最后一个想分享的是嵌套 tuple 的拆解:🎜
rrreee
🎜这个技巧可以很方便的用来拆解巢状嵌套的 tuple. 🎜感谢大家不嫌我话多...
怪我咯2017-04-17 17:52:17
感觉用pandas是不是方便很多
import pandas as pd
df = pd.read_csv('example.txt',sep=' ',header=None)
df = df.astype(str) # 将数字转换为字符串
grouped = df.groupby([0,1])
result = grouped.agg(lambda x:'|'.join(x))
四行就解决了
文档我先保存成example.txt了