2

私はプログラミングにかなり慣れていないので、特定の列で 2 つの .csv ファイルを比較し、追加、削除、および変更をチェックする python プログラムを作成しようとしています。.csv ファイルは両方とも次の形式であり、同じ量の列が含まれ、BillingNumber をキーとして使用します。

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.DictReaderまたはを使用してそれらを辞書にロードできることは理解していますcsv.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()

追加の行がある場合、または行が欠落している場合、その行以降のすべてが異なるものとしてログに記録されるため、正しく機能しません。また、私がやりたいことではない行全体を比較します。これは基本的に単なる出発点であり、ある程度は機能しましたが、必要なものに対して十分に具体的ではありません. 私は本当に始めるのに良い場所を探しています。ありがとう!

4

4 に答える 4

1

csv モジュールを使用して正しい軌道に乗っていたと思います。「BillingNumber」は一意のキーであるため、「古い」請求ファイル用に 1 つの dict を作成し、「新しい」請求ファイル用に別の dict を作成します。

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']

明らかに、比較ごとに個別の print ステートメントを作成することはありません。データ構造を使用して違いを見つける方法を示しているだけです。次に、考えられるすべての BillingNumbers をループして古いものと新しいものとの違いをチェックする関数を作成する必要がありますが、その部分は省略します。

于 2013-02-28T17:34:59.277 に答える
0

これは自分で書く必要がありますか?これがプログラミング演習である場合は、すべての権限をあなたに委ねます。それ以外の場合は、「diff」というツールを探してください。これは、既にアクセスできる形式で存在する可能性があります。テキスト エディタや vim、emacs、notepad++ などの他の多くのツールや、Subversion mercurial や git などのバージョン管理システムに組み込まれています。

車輪を再発明するのではなく、確立された主力製品を使用することをお勧めします。git diff獣です。

于 2013-02-28T16:48:31.440 に答える
0

あなたのコメントを読む:

それは私が理解しようとしているものです。彼らは職場で新しい技術者の求人情報を掲載し、彼らが雇う人はこの問題を解決しなければなりません.

彼らは、コマンドライン fu を探している可能性があります。似たようなもの

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

awk を使用して選択された特定の列を比較するために、 diffツールを使用してbash で機能するコマンド。

これは明らかに Python ベースのソリューションではありません。ただし、このソリューションは単純な UNIX ベースのツールの能力を示しています。

于 2013-02-28T17:13:49.817 に答える
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を使用する方が簡単かもしれません。

于 2013-02-28T17:35:52.403 に答える