搜尋

首頁  >  問答  >  主體

python:怎样合并文档中有重复部分的行?

文档内容如下:

   (数据对)              (信息)
-----------------  ------------------------
  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
....

小白,不懂怎么做,只能想到用字典,好像又行不通,求各位大神帮忙

大家讲道理大家讲道理2805 天前1130

全部回覆(4)我來回復

  • 阿神

    阿神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))

    回覆
    0
  • 阿神

    阿神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
    1. 輸出行的順序要顧及: pr333 先於 pr33w

    2. 專案合併之後的順序要顧及: thisisa 先於 sentence

    這代表我們 所使用的資料型態必須要能維持順序


    其次是速度,我們都知道序列型態是線性搜尋,為了效率,使用映射型態是比較好的.

    三種考量之下,就如同 moling3650 大所言,OrderedDict 是個好選擇.這可以解決行輸出的問題,不過合併項目由於只需要用到key 而不需要用到value 所以使用OrderedDict 有點可惜,不過目前標準庫中沒有OrderSet的選擇,所以只好將就著用一下. OrderedDict 是個好選擇.這可以解決行輸出的問題,不過合併項目由於只需要用到 key 而不需要用到 value 所以使用 OrderedDict 有點可惜,不過目前標準庫中沒有 OrderSet 的選擇,所以只好將就著用一下.

    1. 有關於 OrderedDict 可以參閱 OrderedDict

    2. 其實有一個 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
    或可以自己實作,請參考 OrderedSet (Python recipe)🎜🎜 🎜 🎜 🎜最後linkse7en 大的觀點非常好,這類文件處理的問題,如果能夠邊讀邊寫,邊讀邊處理絕對是🎜有效率🎜(因為只需要進行一次文檔的走訪) (討論請見評論部分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. 🎜

    感謝大家不嫌我話多...

    回覆
    0
  • 怪我咯

    怪我咯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了

    回覆
    0
  • 高洛峰

    高洛峰2017-04-17 17:52:17

    雷雷

    回覆
    0
  • 取消回覆