2013-04-29 92 views
8

Tôi đang cố gắng so sánh hai tệp csv (tệpA và tệpB) và loại bỏ bất kỳ hàng nào khỏi tệpA không được tìm thấy trong tệpB. Tôi muốn có thể thực hiện điều này mà không cần tạo tệp thứ ba. Tôi nghĩ rằng tôi có thể làm điều này bằng cách sử dụng mô-đun nhà văn csv nhưng bây giờ tôi là thứ hai đoán bản thân mình.Cách xóa các hàng CSV trong python

Hiện nay, tôi đang sử dụng đoạn mã sau để ghi dữ liệu so sánh của tôi từ tập tin B:

removal_list = set() 
with open('fileB', 'rb') as file_b: 
    reader1 = csv.reader(file_b) 
    next(reader1) 
    for row in reader1: 
     removal_list.add((row[0], row[2])) 

Đây là nơi tôi bị mắc kẹt và không biết làm thế nào để xóa các hàng:

with open('fileA', 'ab') as file_a: 
    with open('fileB', 'rb') as file_b: 
     writer = csv.writer(file_a) 
      reader2 = csv.reader(file_b) 
      next(reader2) 
      for row in reader2: 
       if (row[0], row[2]) not in removal_list: 
       # If row was not present in file B, Delete it from file A. 
       #stuck here: writer.<HowDoIRemoveRow>(row) 
+1

['sqlite'] (http://docs.python.org/2/library/sqlite3.html) là một cơ sở dữ liệu dựa trên tệp phẳng và trình điều khiển cho nó được bao gồm trong các phiên bản Python hiện đại. Nó có thể là một lựa chọn tốt hơn xem xét những gì bạn đang cố gắng làm. –

+0

Xin lỗi cho câu hỏi ngớ ngẩn nhưng điều này sẽ tạo ra một bản sao chính xác của tập tinB, phải không? –

Trả lời

7

giải pháp này sử dụng fileinput với inplace=True, mà viết vào một tập tin tạm thời và sau đó tự động đổi tên nó vào cuối tập tin của bạn Tên. Bạn không thể xóa hàng khỏi một tệp nhưng bạn có thể viết lại chỉ với những hàng bạn muốn.

nếu đối số từ khóa inplace=1 được chuyển cho fileinput.input() hay để các nhà xây dựng FileInput, các tập tin được chuyển đến một tập tin sao lưu và đầu ra tiêu chuẩn là hướng đến các tập tin đầu vào (nếu một tập tin cùng tên như tập tin sao lưu đã tồn tại, nó sẽ được thay thế âm thầm). Điều này làm cho nó có thể viết một bộ lọc mà viết lại tập tin đầu vào của nó tại chỗ.

fileA

h1,h2,h3 
a,b,c 
d,e,f 
g,h,i 
j,k,l 

fileB

h1,h2,h3 
a,b,c 
1,2,3 
g,h,i 
4,5,6 

import fileinput, sys, csv 

with open('fileB', 'rb') as file_b: 
    r = csv.reader(file_b) 
    next(r) #skip header 
    seen = {(row[0], row[2]) for row in r} 

f = fileinput.input('fileA', inplace=True) # sys.stdout is redirected to the file 
print next(f), # write header as first line 

w = csv.writer(sys.stdout) 
for row in csv.reader(f): 
    if (row[0], row[2]) in seen: # write it if it's in B 
     w.writerow(row) 

fileA

h1,h2,h3 
a,b,c  
g,h,i 
+0

Một cải tiến tinh tế không được giải quyết trong phần giải thích: mã này sử dụng một tập hợp, một cấu trúc dữ liệu tối ưu hơn nhiều để trả lời "là dữ liệu này có hiện diện không?" hơn một danh sách (mà phải được lặp lại qua mỗi lần). –

+0

@David Op cũng sử dụng một bộ mặc dù – jamylak

+0

D'oh. Anh ta rõ ràng đã làm. Vâng, một chút lời khuyên - đừng gọi nó là "danh sách" loại bỏ, hoặc những người đứng đầu xương như tôi sẽ bị nhầm lẫn với kiểu của biến đó. =) –

3

CSV không phải là định dạng cơ sở dữ liệu. Nó được đọc và viết như một toàn thể. Bạn không thể xóa các hàng ở giữa. Vì vậy, cách duy nhất để làm điều này mà không cần tạo một tệp thứ ba là đọc toàn bộ tệp trong bộ nhớ và sau đó ghi nó ra, mà không có các hàng vi phạm.

Nhưng nói chung tốt hơn nên sử dụng tệp thứ ba.

3

Khi Lennart được mô tả, bạn không thể sửa đổi tệp CSV tại chỗ khi bạn lặp lại trên đó.

Nếu bạn thực sự phản đối việc tạo tệp thứ ba, bạn có thể muốn xem xét sử dụng bộ đệm chuỗi với StringIO, ý tưởng là bạn xây dựng nội dung mong muốn mới của tệp A trong bộ nhớ. Vào cuối kịch bản của bạn, bạn có thể viết các nội dung của bộ đệm trên tập A.

from cStringIO import StringIO 


with open('fileB', 'rb') as file_b: 
    new_a_buf = StringIO() 
    writer = csv.writer(new_a_buf) 
    reader2 = csv.reader(file_b) 
    next(reader2) 
    for row in reader2: 
     if (row[0], row[2]) not in removal_list: 
      writer.writerow(row) 

# At this point, the contents (new_a_buf) exist in memory 
with open('fileA', 'wb') as file_a: 
    file_a.write(new_a_buf.getvalue()) 
+0

Một lời cảnh báo ở đây: bạn có thể làm cạn kiệt bộ nhớ khả dụng cho hệ thống của mình nếu các tệp đầu vào của bạn lớn. –

+0

Bạn cũng có thể chỉ cần ghi vào một tập tin khác và đổi tên nó ở cuối, đó là những gì giải pháp của tôi không – jamylak

+0

@ jamylak, tôi hoàn toàn đồng ý với bạn. Và đó chính là điều tôi sẽ làm trong tình huống này. Tôi chỉ thấy điều này sẽ hữu ích trong đó về mặt kỹ thuật đáp ứng những gì người hỏi đang tìm kiếm. –

Các vấn đề liên quan