2015-01-07 10 views
0

두 개의 csv 파일이 있으며 각각 13 개의 열이 있습니다.두 개의 CSV를 데이터가 보관되는 규칙을 사용하여 거의 동일한 세트로 병합하는 방법은 무엇입니까? (Ruby 및 FasterCSV 사용)

각 행의 첫 번째 열에는 고유 한 문자열이 있습니다. 일부는 각 파일에 복제되고, 일부는 하나의 파일에만 존재합니다.

행이 하나의 파일에만있는 경우 새 파일에 보관하고 싶습니다.

둘 다 존재하는 경우 특정 값을 가진 (또는 특정 값이없는) 동일한 행의 특정 열을 유지하고 싶습니다.

파일 1 :

D600-DS-1991, name1, address1, date1 
D601-DS-1991, name2, address2, date2 
D601-DS-1992, name3, address3, date3 

파일 2 : 네 번째 열은 date 대신 time 포함되어 있기 때문에

D600-DS-1991, name1, address1, time1 
D601-DS-1992, dave1, address2, date2 

내가 첫 번째 파일의 첫 번째 행을 유지하는 것입니다 예를 들어

. 첫 번째 열, 첫 번째 행 값이 고유하기 때문에 첫 번째 파일의 두 번째 행을 유지합니다. 두 번째 파일의 두 번째 행은 두 번째 열에 "name #"이외의 텍스트가 포함되어 있으므로 새 파일의 세 번째 행으로 유지합니다.

먼저 모든 고유 값을 서로 매핑하여 일부 파일이 공백이거나 필러 데이터 만있는 경우에도 동일한 수의 항목을 포함해야합니까?

저는 루비와 파이썬 만 알고 있습니다 ...하지만 코드를 더 잘 이해할 수 있기 때문에 가능한 한 단일 루비 파일로 해결하는 것을 선호합니다. 루비에서 할 수 없다면 다르게 대답하십시오!

+0

지금까지 무엇을 시도 했습니까? 그대로, 이것은 단지 누군가가 당신을 위해 더러운 일을하도록 요청하는 것입니다. –

+0

첫 번째 파일이 항상 깨끗한 지 또는 부실 행이 포함될 수 있습니까? 그렇다면 두 파일 모두 특정 ID에 대해 네 번째 열에'time'이 있으면 어떻게됩니까? –

+0

@Anthony "각 파일에 중복 된 파일이 있습니다."라는 말은 두 파일 모두에 항목이있을 수 있음을 의미합니다. –

답변

0

내가 내 솔루션 슈퍼 행복하지 않다하지만 작동 :

require 'csv' 

def readcsv(filename) 
    csv = {} 
    CSV.foreach(filename) do |line| 
    csv[line[0]] = { name: line[1], address: line[2], date: line[3] } 
    end 
    csv 
end 

csv1 = readcsv('orders1.csv') 
csv2 = readcsv('orders2.csv') 

results = {} 
csv1.each do |id, val| 
    unless csv2[id] 
    results[id] = val # checks to see if it only exists in 1 file 
    next 
    end 

    #see if name exists 
    if (val[:name] =~ /name/) && (csv2[id]) && (csv2[id][:name] =~ /name/).nil? 
    csv1.delete(id) 
    end 

    #missing some if statement regarding date vs. time 
end 

results = results.merge(csv2) # merge together whatever is remaining 

CSV.open('newfile.csv', 'w') do |csv| 
    results.each do |key, val| 
    row = [] 
    csv << (row.push(key, val.values)).flatten 
    end 
end 

newfile.csv의 출력 :

D601-DS-1991, name2, address2, date2 
D600-DS-1991, name1, address1, time1 
D601-DS-1992, dave1, address2, date2 
0

내가 당신에게 전체 코드를 제공하지 않습니다 그러나 여기에서 이러한 문제에 대한 일반적인 접근 방식 :

require 'csv' 

# list of csv files to read 
files = ['a.csv', 'b.csv'] 

# used to resolve conflicts when we have a existing entry with same id 
# here, we prefer the new entry if its fourth column starts with `'date'` 
# this also means that the last file in the list above wins if both entries are valid. 
def resolve_conflict(existing_entry, new_entry) 
    if new_entry[3].start_with? 'date' 
    new_entry 
    else 
    existing_entry 
    end 
end 

# keep a hash of entries, with the unique id as key. 
# we use this id to detect duplicate entries later on. 
entries = {} 

CSV.foreach(file) do |new_entry| 
    # get id (first column) from row 
    id = new_entry[0] 

    # see if we have a conflicting entry 
    existing_entry = entries[id] 
    if existing_entry.nil? 
    # no conflict, just save the row 
    entries[id] = new_entry 
    else 
    # resolve conflict and save that 
    entries[id] = resolve_conflict(existing_entry, new_entry) 
    end 
end 

# now all conflicts are resolved 
# note that stale rows from the first file could now be in the result 
# you might want to filter them out as well 
# we can now build a new csv file with the result 
CSV.open("result.csv", "w") do |csv| 
    entries.values.each do |row| 
    csv << row 
    end 
end