2009-05-05 16 views
8

Więc mam dwa pliki .csv, gdzie pierwsza linia w pliku 1 jest:Łączenie 2 pliki .csv przez wspólne kolumny

MPID,Title,Description,Model,Category ID,Category Description,Subcategory ID,Subcategory Description,Manufacturer ID,Manufacturer Description,URL,Manufacturer (Brand) URL,Image URL,AR Price,Price,Ship Price,Stock,Condition 

Pierwszy wiersz z pliku 2:

Regular Price,Sale Price,Manufacturer Name,Model Number,Retailer Category,Buy URL,Product Name,Availability,Shipping Cost,Condition,MPID,Image URL,UPC,Description 

a następnie reszta każdego pliku jest wypełniona informacją.

Jak widać, oba pliki mają wspólne pole o nazwie MPID (plik 1: col 1, plik 2: col 9, gdzie pierwszy col to col 1).

Chciałbym stworzyć nowy plik, który połączy te dwa pliki, patrząc na tę kolumnę (jak w: jeśli istnieje MPID, który jest w obu plikach, to w nowym pliku ten MPID pojawi się z obu wiersz z pliku 1 i jego wiersz z pliku 2). JEŚLI jeden MPID pojawia się tylko w jednym pliku, powinien również przejść do tego połączonego pliku.

Pliki nie są w żaden sposób sortowane.

Jak to zrobić na komputerze debian ze skryptem powłoki lub pythonem?

Dzięki.

EDYCJA: Oba pliki nie mają przecinków innych niż te, oddzielające pola.

Odpowiedz

0

Wygląda na to, że próbujesz wykonać skrypt powłoki, co zwykle odbywa się za pomocą serwera SQL. Czy jest możliwe użycie SQL do tego zadania? Na przykład możesz zaimportować oba pliki do mysql, następnie utworzyć połączenie, a następnie wyeksportować je do pliku CSV.

1

Musisz sprawdzić komendę join w powłoce. Będziesz także potrzebował posortować dane i prawdopodobnie stracisz pierwsze wiersze. Cały proces spadnie, jeśli którykolwiek z danych zawiera przecinki. Lub musisz przetworzyć dane za pomocą procesu wrażliwego na CSV, który wprowadza inny separator pól (być może control-A), którego możesz użyć do jednoznacznego podziału pól.

Alternatywą, używając Pythona, odczytuje dwa pliki w pary słowników (wpisane na wspólnej kolumnie (kolumnach)), a następnie użyć pętli, aby objąć wszystkie elementy w mniejszym z dwóch słowników, szukając dopasowania wartości w drugim. (Jest to podstawowe przetwarzanie zapytań w pętli zagnieżdżonej.)

+1

przyłączenia działa świetnie; ale pliki wejściowe muszą być posortowane na kluczu. również nie może odczytać dowolnych plików csv. w szczególności, przecinek w cytowanym polu przesunie wszystkie pola do tego rekordu: – Javier

+0

@Javier: agreed - i dlatego zaktualizowałem swoją odpowiedź, aby powiedzieć tyle, nawet nie widząc twojego komentarza (który był prawdopodobnie w przygotowaniu w tym samym czasie byłem redagowanie). –

13
sort -t , -k index1 file1 > sorted1 
sort -t , -k index2 file2 > sorted2 
join -t , -1 index1 -2 index2 -a 1 -a 2 sorted1 sorted2 
+6

uwaga na cudzysłowy! nie sortuj ani nie dołączaj do żadnej oferty – Javier

9

Jest to klasyczny problem "łączenia z relacjami".

Masz kilka algorytmów.

  • Zagnieżdżone pętle. Czytasz z jednego pliku, aby wybrać rekord "master". Czytasz cały inny plik lokalizując wszystkie "szczegółowe" rekordy, które pasują do wzorca. To jest zły pomysł.

  • Sort-Merge. Sortujesz każdy plik w tymczasową kopię na podstawie wspólnego klucza. Następnie łączysz oba pliki, odczytując wzorzec, a następnie odczytując wszystkie pasujące wiersze z detalu i zapisując scalone rekordy.

  • Wyszukiwanie. Czytasz jeden z plików w całości w słowniku w pamięci, indeksowanym przez pole klucza. Może to być trudne w przypadku pliku szczegółów, w którym będziesz mieć wiele dzieci na klucz. Następnie czytasz drugi plik i wyszukuje pasujące rekordy w słowniku.

Spośród nich sortowanie jest często najszybsze. Odbywa się to w całości przy użyciu polecenia unix sort.

Lookup Realizacja

import csv 
import collections 

index = collections.defaultdict(list) 

file1= open("someFile", "rb") 
rdr= csv.DictReader(file1) 
for row in rdr: 
    index[row['MPID']].append(row) 
file1.close() 

file2= open("anotherFile", "rb") 
rdr= csv.DictReader(file2) 
for row in rdr: 
    print row, index[row['MPID']] 
file2.close() 
+0

Ponieważ Python 2.2 wierzę, DictReader nie implementuje __getitem__. Dokonano tego ze względu na szybkość. Tak więc kod: index[rdr['MPID']].append(row) zakończy się niepowodzeniem z wystąpieniem AttributeError: DictReader nie ma atrybutu "__getitem__" – uman

+0

@uman: Wyniki DictReadera są pierwszorzędnym obiektem 'dict'. Wszystkie nietknięte metody "dyktują". –

+0

@ S.Lott: być może twój kod był niepoprawny. Jestem bardzo zardzewiały w Pythonie, ale próba użycia przykładu MPID z twoim kodem powoduje AttributeError. Zobacz: http://pastebin.com/VJgSfA3u P.S. Czy ktoś wie, jak umieszczać formatowanie w komentarzach? – uman

0

Można spojrzeć na moim projekcie FOSS CSVfix, który jest edytorem strumieni do manipulowania plików CSV. Obsługuje połączenia między innymi funkcjami i nie wymaga używania skryptów.

0

Do łączenia wielu plików (nawet> 2) w oparciu o jedną lub więcej wspólnych kolumn, jednym z najlepszych i skutecznych podejść w Pythonie byłoby użycie "browaru". Można nawet określić, które pola należy uwzględnić przy łączeniu i jakie pola należy zapisać.

import brewery 
from brewery 
import ds 
import sys 

sources = [ 
    {"file": "grants_2008.csv", 
    "fields": ["receiver", "amount", "date"]}, 
    {"file": "grants_2009.csv", 
    "fields": ["id", "receiver", "amount", "contract_number", "date"]}, 
    {"file": "grants_2010.csv", 
    "fields": ["receiver", "subject", "requested_amount", "amount", "date"]} 
] 

Utwórz listę wszystkich pól i dodać nazwę pliku do przechowywania informacji o pochodzeniu danych records.Go przez definicjami źródłowymi i zbierać pola:

for source in sources: 
    for field in source["fields"]: 
     if field not in all_fields: 

out = ds.CSVDataTarget("merged.csv") 
out.fields = brewery.FieldList(all_fields) 
out.initialize() 

for source in sources: 

    path = source["file"] 

# Initialize data source: skip reading of headers 
# use XLSDataSource for XLS files 
# We ignore the fields in the header, because we have set-up fields 
# previously. We need to skip the header row. 

    src = ds.CSVDataSource(path,read_header=False,skip_rows=1) 

    src.fields = ds.FieldList(source["fields"]) 

    src.initialize() 


    for record in src.records(): 

    # Add file reference into ouput - to know where the row comes from 
    record["file"] = path 

     out.append(record) 

# Close the source stream 

    src.finalize() 


cat merged.csv | brewery pipe pretty_printer 
Powiązane problemy