2013-02-28 49 views
2

我在編程方面相當新,我正在編寫一個python程序,它將根據特定列比較2個.csv文件並檢查添加,刪除和修改。該.csv文件都按以下格式,包含列相同數量,並使用BillingNumber爲重點:將2個.csv文件與Python進行比較,然後輸出結果

BillingNumber,CustomerName,IsActive,IsCreditHold,IsPayScan,City,State 
"2","CHARLIE RYAN","Yes","No","Yes","Reading","PA" 
"3","INSURANCE BILLS","","","","","" 
"4","AAA","","","","","" 

我需要比較僅列0,1,2,4,我曾嘗試許多不同的方式來完成這一點,但我沒有任何運氣。我知道我可以使用csv.DictReadercsv.reader將它們加載到字典中,但在此之後我卡住了。在將它們加載到內存後,我不確定在哪裏或如何啓動。

我想這之前:

import time 
old_lines = set((line.strip() for line in open(r'Old/file1.csv', 'r+'))) 
file_new = open(r'New/file2.csv', 'r+') 

choice = 0 
choice = int(input('\nPlease choose your result format.\nEnter 1 for .txt, 2 for .csv or 3 for .json\n')) 
time.sleep(1) 
print(".") 
time.sleep(1) 
print("..") 
time.sleep(1) 
print("...") 
time.sleep(1) 
print("....") 
time.sleep(1) 
print('Done! Check "Different" folder for results.\n') 
if choice == 1: 
    file_diff = open(r'Different/diff.txt', 'w') 
elif choice == 2: 
    file_diff = open(r'Different/diff.csv', 'w') 
elif choice == 3: 
    file_diff = open(r'Different/diff.json', "w") 
else: 
    print ("You MUST enter 1, 2 or 3") 
    exit() 

for line in file_new: 
    if line.strip() not in old_lines: 
     file_diff.write("** ERROR! Entry "+ line + "** Does not match previous file\n\n") 
file_new.close() 
file_diff.close() 

,因爲如果有一個額外的線,或者缺少一個,它會記錄該行不同的後一切它不能正常工作。它也比較了我不想做的整個行。這基本上只是一個起點,雖然它有效,但它不足以滿足我的需求。我真的只是尋找一個開始的好地方。謝謝!

+0

這將是開始的地方http://docs.python.org/2/library/csv.html – danodonovan 2013-02-28 16:39:35

+2

所以這聽起來像你正在嘗試編寫一個diff程序。這是一個相當深入的話題。嘗試http://stackoverflow.com/questions/805626/diff-algorithm或http://stackoverflow.com/questions/5897983/diff-algorithm-implementation-in-python。 – Hoopdady 2013-02-28 16:39:42

+1

「我不確定將它們加載到內存後到底在哪裏或如何啓動」。這是有原因的。你沒有嚴格描述你想要的東西。您說過要「按特定列比較2個.csv文件並檢查添加,刪除和修改」。正如Hoopdady所說,這個簡單的陳述涵蓋了很多。我會首先仔細地寫下你想要檢查的內容(比如:如果一列中有一個加法,另一列中有一個刪除,那該怎麼辦)。一旦你足夠好地提出你的問題,實現將變得更容易。 – Wilduck 2013-02-28 16:41:54

回答

1

我想你是在正確的軌道上使用csv模塊。由於「BillingNumber」是一個獨特的關鍵,我想創建一個字典的「老」的計費文件,另一個是「新」的計費文件:

import csv 

def make_billing_dict(csv_dict_reader): 
    bdict = {} 
    for entry in csv_dict_reader: 
     key = entry['BillingNumber'] 
     bdict[key] = entry 
    return bdict 

with open('old.csv') as csv_file: 
    old = csv.DictReader(csv_file) 
    old_bills = make_billing_dict(old) 

導致這個數據結構爲old_bills

{'2': {'BillingNumber': '2', 
     'City': 'Reading', 
     'CustomerName': 'CHARLIE RYAN', 
     'IsActive': 'Yes', 
     'IsCreditHold': 'No', 
     'IsPayScan': 'Yes', 
     'State': 'PA'}, 
'3': {'BillingNumber': '3', 
     'City': '', 
     'CustomerName': 'INSURANCE BILLS', 
     'IsActive': '', 
     'IsCreditHold': '', 
     'IsPayScan': '', 
     'State': ''}, 
'4': {'BillingNumber': '4', 
     'City': '', 
     'CustomerName': 'AAA', 
     'IsActive': '', 
     'IsCreditHold': '', 
     'IsPayScan': '', 
     'State': ''}} 

一旦你創建了「新」的計費文件相同的數據結構,你可以很容易地找到差異:

# Keys that are in old_bills, but not new_bills 
print set(old_bills.keys()) - set(new_bills.keys()) 

# Keys that are in new_bills, but not old_bills 
print set(new_bills.keys()) - set(old_bills.keys()) 

# Compare columns for same billing records 
# Will print True or False 
print old_bills['2']['CustomerName'] == new_bills['2']['CustomerName'] 
print old_bills['2']['IsActive'] == new_bills['2']['IsActive'] 

很顯然,你不會寫一個單獨的打印統計爲每個比較提供參考。我只是在演示如何使用數據結構來找出差異。接下來,您應該編寫一個函數來循環遍歷所有可能的BillingNumbers,並檢查新舊版本之間的差異,但我會爲您保留該部分。

0

你自己寫這個嗎?如果這是一個編程練習,給你所有的權力。否則,請查找名爲「diff」的工具,該工具可能以您已有權訪問的某種形式存在。它內置於許多其他工具中,如文本編輯器,如vim,emacs和notepad ++,以及版本控制系統,如subversion mercurial和git。

我建議你使用既定的主力而不是重新發明輪子。 git diff是一隻野獸。

+0

這只是我想弄明白的。他們爲工作中的新技術人員提供了一份工作清單,而他們將僱用的人員必須解決這個問題。我只是想看看我是否能夠出於好奇而做到這一點,但在嘗試了大約一週之後,我一直無法做到。運營技術部門的人說這應該很容易,但似乎比他原先所說的更深入。我有時會感到無聊,這是我嘗試的事情,但現在我想看看它的工作。如果這取決於我,我只是將它們加載到Excel中並進行比較。 – user2120375 2013-02-28 17:02:07

+0

他們絕對不希望你從頭開始構建一個工具。 – 2013-02-28 18:10:03

0

閱讀您的評論:

這只是一些我試圖弄清楚。他們爲工作中的新技術人員提供了一份工作清單,而他們將僱用的人員必須解決這個問題。

他們很可能正在尋找一些命令行fu。一個類似於

diff <(awk -F "\"*,\"*" '{print $1,$2,$3,$5}' csv1.csv) <(awk -F "\"*,\"*" '{print $1,$2,$3,$5}' csv2.csv) 

的命令will work in bash,使用diff工具,比較某些列,selected using awk

這顯然不是一個基於python的解決方案。但是,這個解決方案確實證明了簡單的基於Unix的工具的強大功能。

+0

確實非常酷。當我運行它時效果很好,但它在打印差異之前在第一行放置了一些奇怪的數字:4965a4966,4967。此外,這是一個相當艱難的程序,用python編寫,還是我只是在我的技能背後? – user2120375 2013-02-28 17:22:55

+0

用python替換'awk'的部分是相當容易的。但是,編寫自己的'diff'工具可能會非常複雜。 Fortunatley,Python是「包含電池」,並且已經包含一個差異庫:http://docs.python.org/2/library/difflib.html。該實現是在Python中,所以你可以看看你是否想重新實現它http://svn.python.org/projects/python/trunk/Lib/difflib.py – Wilduck 2013-02-28 17:26:45

+1

它聽起來比它更容易。我明白我想要它做什麼,但我還沒弄清楚如何用python實現它。我會繼續努力。感謝所有的答覆。 – user2120375 2013-02-28 17:31:00

0

因爲這些東西的要求有一個傾向,我認爲這是值得把數據放入SQLite數據庫。

作爲檢測一行是否被刪除或只是新的邏輯可能會很難實現。

在下面我推測BillingNumber是id並且不會被改變。

import sqlite3 
con = sqlite3.connect(":memory:") 

cursor = con.cursor() 
columns = "BillingNumber,CustomerName,IsActive,IsCreditHold,IsPayScan,City,State" 
cursor.execute("CREATE TABLE left (%s);" % columns) 
cursor.execute("CREATE TABLE right (%s);" % columns) 

placeholders = ",".join("?" * len(columns.split(','))) 

import csv 
def reader(filename): 
    for (lineno, line) in enumerate(open(filename)): 
     if lineno > 0: # skip header 
      yield line 

def load_table(tablebname, filename): 
    for row in csv.reader(reader(filename)): 
     cursor.execute("INSERT INTO %s VALUES(%s);" % (tablebname, placeholders), row) 

load_table("left", "left.csv") 
load_table("right", "right.csv") 

if False: 
    print "LEFT" 
    for row in cursor.execute("SELECT * from left;"): 
     print row[0] 

     print "RIGHT" 
     for row in cursor.execute("SELECT * from right;"): 
      print row 

def dataset(tablename, columns): 
    for row in cursor.execute("SELECT * from %s;" % tablename): 
     yield tuple(row[x] for x in columns) 

# To use if raw data required.  
#left_dataset = dataset("left", [0,1,2,4]) 
#right_dataset = dataset("right", [0,1,2,4]) 

# COMPARE functions. 
def different_rows(): 
    q = """SELECT left.*, right.* 
    FROM left, right 
    WHERE left.BillingNumber = right.BillingNumber 
    AND (left.CustomerName != right.CustomerName OR 
      left.IsActive  != right.IsActive OR 
      left.IsPayScan != right.IsPayScan) 
      ; 
    """ 
    for row in cursor.execute(q): 
     print "DIFFERENCE", row 

def new_rows(): 
    q = """SELECT right.* 
    FROM right 
    WHERE right.BillingNumber NOT IN (SELECT BillingNumber FROM left) 
      ; 
    """ 
    for row in cursor.execute(q): 
     print "NEW", row 

different_rows() 
new_rows() 

的OP必須編寫不同功能的數據,但我比較使用SQL可能更容易在整體上。

相關問題